14,469
edits
Falterfire (talk | contribs) (Fixed some stuff related to Potions and added Astrology as a use) |
(_getItemUseTable: Amend links for Agility uses to link to specific obstacle/pillar) |
||
(29 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local Constants = require('Module:Constants') | local Constants = require('Module:Constants') | ||
local Shared = require('Module:Shared') | local Shared = require('Module:Shared') | ||
local GameData = require('Module:GameData') | |||
local SkillData = GameData.skillData | |||
local Magic = require('Module:Magic') | local Magic = require('Module:Magic') | ||
local Areas = require('Module:CombatAreas') | local Areas = require('Module:CombatAreas') | ||
Line 13: | Line 11: | ||
local Agility = require('Module:Skills/Agility') | local Agility = require('Module:Skills/Agility') | ||
local Shop = require('Module:Shop') | local Shop = require('Module:Shop') | ||
--Brute forcing some item uses to make things easier | --Brute forcing some item uses to make things easier | ||
local itemUseArray = { | local itemUseArray = { | ||
Agility = {}, | |||
Astrology = {'melvorF:Stardust', 'melvorF:Golden_Stardust'}, | |||
Attack = {}, | |||
Cartography = {'melvorD:Crown_of_Rhaelyx'}, | |||
Combat = {'melvorF:Gold_Emerald_Ring', 'melvorD:Obsidian_Cape', 'melvorF:Throwing_Power_Gloves'}, | |||
Cooking = {'melvorD:Cooking_Gloves', 'melvorD:Crown_of_Rhaelyx'}, | |||
Crafting = {'melvorD:Crown_of_Rhaelyx'}, | |||
Defence = {}, | |||
Farming = {'melvorD:Compost', 'melvorD:Weird_Gloop', 'melvorD:Bobs_Rake'}, | |||
Firemaking = {'melvorD:Crown_of_Rhaelyx'}, | |||
Fishing = {'melvorD:Amulet_of_Fishing', 'melvorD:Message_In_A_Bottle', 'melvorD:Barbarian_Gloves'}, | |||
Fletching = {'melvorD:Crown_of_Rhaelyx'}, | |||
Herblore = {'melvorD:Crown_of_Rhaelyx'}, | |||
Hitpoints = {}, | |||
Magic = {}, | |||
Mining = {'melvorD:Mining_Gloves', 'melvorD:Gem_Gloves'}, | |||
Prayer = {}, | |||
Ranged = {}, | |||
Runecrafting = {'melvorD:Crown_of_Rhaelyx'}, | |||
Slayer = {}, | |||
Smithing = {'melvorD:Smithing_Gloves', 'melvorD:Crown_of_Rhaelyx'}, | |||
Strength = {}, | |||
Summoning = {'melvorD:Crown_of_Rhaelyx'}, | |||
Thieving = {'melvorF:Chapeau_Noir', 'melvorF:Thieving_Gloves', 'melvorF:Gloves_of_Silence'}, | |||
Township = {}, | |||
Woodcutting = {}, | |||
} | |||
} | |||
function p._getItemUses(item, asList, addCategories) | function p._getItemUses(item, asList, addCategories) | ||
-- Another fun one. This time getting all the different possible ways an item can be used | |||
local categoryArray = {} | |||
local skillUses = {} | |||
local otherUses = {} | |||
local otherUseText = { | |||
["Combat"] = Icons.Icon({'Combat'}), | |||
["Upgrade"] = '[[Upgrading Items]]', | |||
["Food"] = '[[Food]]', | |||
["Chest"] = '[[Chest Drop Tables|Can Be Opened]]', | |||
["Mastery"] = Icons.Icon({'Mastery'}), | |||
["AllSkills"] = 'All skills', | |||
["AltMagic"] = Icons.Icon({'Alt. Magic', type='skill'}), | |||
["ChargeStone"] = 'Powering ' .. Icons.Icon({'Crown of Rhaelyx', type='item'}), | |||
["Shop"] = Icons.Icon({'Shop'}), | |||
["TownshipTask"] = Icons.Icon({'Tasks', type='township'}) | |||
} | |||
local addUse = function(useName) | |||
local skillID = Constants.getSkillID(useName) | |||
if skillID == nil then | |||
-- May have been passed a skill ID instead | |||
local skillName = Constants.getSkillName(useName) | |||
if skillName ~= nil then | |||
skillID = useName | |||
skillUses[skillID] = skillName | |||
end | |||
else | |||
skillUses[skillID] = useName | |||
end | |||
if skillID == nil and not otherUses[useName] then | |||
otherUses[useName] = true | |||
end | |||
end | |||
local hasUse = function(useName) | |||
local skillID = Constants.getSkillID(useName) or (Constants.getSkillName(useName) ~= nil and useName) | |||
if skillID ~= nil then | |||
return (skillUses[skillID] ~= nil) or false | |||
else | |||
return otherUses[useName] or false | |||
end | |||
end | end | ||
-- Check for any overrides within itemUseArray | |||
for useName, itemList in pairs(itemUseArray) do | |||
if Shared.contains(itemList, item.id) then | |||
addUse(useName) | |||
end | |||
end | |||
-- If the item has any modifiers that affect a given skill, add it to those tables | |||
-- Added special handling for Mastery Tokens since they were being incorrectly flagged as usable for all skills | |||
if item.modifiers ~= nil then | |||
if item.modifiers.masteryToken ~= nil then | |||
-- Mastery tokens | |||
addUse('Mastery') | |||
else | |||
local globalMods = { | |||
'increasedChanceToDoubleItemsGlobal', | |||
'decreasedChanceToDoubleItemsGlobal', | |||
'increasedGlobalSkillIntervalPercent', | |||
'decreasedGlobalSkillIntervalPercent', | |||
'increasedGlobalSkillXP', | |||
'decreasedGlobalSkillXP' | |||
} | |||
for i, globalMod in ipairs(globalMods) do | |||
if item.modifiers[globalMod] ~= nil then | |||
addUse('AllSkills') | |||
break | |||
end | |||
end | |||
if not hasUse('AllSkills') then | |||
local skillArray = Constants.getModifierSkills(item.modifiers) | |||
for i, skillName in ipairs(skillArray) do | |||
addUse(skillName) | |||
end | |||
end | |||
end | |||
end | |||
--First things added to the list are non-skill things that are easy to check | |||
if not hasUse('Combat') and (Items.hasCombatStats(item) or item.specialAttacks ~= nil) then | |||
addUse('Combat') | |||
end | |||
-- Check if the item is an entry requirement for any Slayer area | |||
if not hasUse('Slayer') and (item.validSlots ~= nil or item.occupiesSlots ~= nil or item.equipmentStats ~= nil) then | |||
local slayerAreas = Areas.getAreas(function(area) return area.type == 'slayerArea' and type(area.entryRequirements) == 'table' end) | |||
for i, area in ipairs(slayerAreas) do | |||
for j, req in ipairs(area.entryRequirements) do | |||
if req.type == "SlayerItem" and req.itemID == item.id then | |||
addUse('Slayer') | |||
break | |||
end | |||
end | |||
if hasUse('Slayer') then | |||
break | |||
end | |||
end | |||
end | |||
-- Is the item a cost in an upgrade? | |||
for i, upgrade in ipairs(GameData.rawData.itemUpgrades) do | |||
for j, itemCost in ipairs(upgrade.itemCosts) do | |||
if itemCost.id == item.id then | |||
addUse('Upgrade') | |||
table.insert(categoryArray, '[[Category:Upgradeable Items]]') | |||
break | |||
end | |||
end | |||
if hasUse('Upgrade') then | |||
break | |||
end | |||
end | |||
if item.healsFor ~= nil then | |||
table.insert(categoryArray, '[[Category:Food Items]]') | |||
addUse('Food') | |||
end | |||
if item.dropTable ~= nil then | |||
table.insert(categoryArray, '[[Category:Openable Items]]') | |||
addUse('Chest') | |||
end | |||
-- Cooking, Smithing, Fletching, Crafting, Runecrafting, Herblore | |||
-- All have somewhat consistent recipe data structures | |||
local recipeSkillIDs = { | |||
'melvorD:Cooking', | |||
'melvorD:Smithing', | |||
'melvorD:Fletching', | |||
'melvorD:Crafting', | |||
'melvorD:Runecrafting', | |||
'melvorD:Herblore' | |||
} | |||
for i, recipeSkillID in ipairs(recipeSkillIDs) do | |||
if not hasUse(recipeSkillID) then | |||
local _, localSkillID = GameData.getLocalID(recipeSkillID) | |||
-- Iterate over all recipes for the current skill | |||
for j, recipe in ipairs(SkillData[localSkillID].recipes) do | |||
for k, itemCost in ipairs(recipe.itemCosts) do | |||
if itemCost.id == item.id then | |||
addUse(recipeSkillID) | |||
break | |||
end | |||
end | |||
-- Some items (such as Arrow shafts) have multiple recipes | |||
if not hasUse(recipeSkillID) and type(recipe.alternativeCosts) == 'table' then | |||
for k, altCost in ipairs(recipe.alternativeCosts) do | |||
for m, itemCost in ipairs(altCost.itemCosts) do | |||
if itemCost.id == item.id then | |||
addUse(recipeSkillID) | |||
break | |||
end | |||
end | |||
if hasUse(recipeSkillID) then | |||
break | |||
end | |||
end | |||
end | |||
if hasUse(recipeSkillID) then | |||
break | |||
end | |||
end | |||
end | |||
end | |||
-- Firemaking | |||
if not hasUse('melvorD:Firemaking') then | |||
for i, recipe in ipairs(SkillData.Firemaking.logs) do | |||
if recipe.logID == item.id then | |||
addUse('melvorD:Firemaking') | |||
break | |||
end | |||
end | |||
end | |||
-- Farming | |||
if not hasUse('melvorD:Farming') then | |||
for i, recipe in ipairs(SkillData.Farming.recipes) do | |||
if recipe.seedCost.id == item.id then | |||
addUse('melvorD:Farming') | |||
break | |||
end | |||
end | |||
end | |||
-- Agility | |||
if not hasUse('melvorD:Agility') and not Shared.tableIsEmpty(Agility.getObstaclesForItem(item.id)) then | |||
addUse('melvorD:Agility') | |||
end | |||
-- Summoning | |||
if not hasUse('melvorD:Summoning') then | |||
for i, recipe in ipairs(SkillData.Summoning.recipes) do | |||
-- Tablets & Non-shard items | |||
if recipe.productID == item.id or Shared.contains(recipe.nonShardItemCosts, item.id) then | |||
addUse('melvorD:Summoning') | |||
break | |||
else | |||
-- Shards | |||
for j, itemCost in ipairs(recipe.itemCosts) do | |||
if itemCost.id == item.id then | |||
addUse('melvorD:Summoning') | |||
break | |||
end | |||
end | |||
end | |||
end | |||
end | |||
-- Prayer | |||
if item.prayerPoints ~= nil then | |||
table.insert(categoryArray, '[[Category:Buriable Items]]') | |||
if not hasUse('melvorD:Prayer') then | |||
addUse('melvorD:Prayer') | |||
end | |||
end | |||
-- Magic | |||
if not (hasUse('Magic') and hasUse('AltMagic')) then | |||
-- First check if the item its self is used in any spells | |||
local spellList = Magic.getSpellsUsingItem(item.id, true) | |||
for i, spell in ipairs(spellList) do | |||
local useKey = (spell.type == 'altMagic' and 'AltMagic' or 'Magic') | |||
if not hasUse(useKey) then | |||
addUse(useKey) | |||
end | |||
end | |||
-- Check if the item provides runes, if it does check where they are used also | |||
if item.providedRunes ~= nil then | |||
for i, rune in ipairs(item.providedRunes) do | |||
if hasUse('Magic') and hasUse('AltMagic') then | |||
break | |||
else | |||
local spellList = Magic.getSpellsUsingItem(rune.id, false) | |||
for j, spell in ipairs(spellList) do | |||
local useKey = (spell.type == 'altMagic' and 'AltMagic' or 'Magic') | |||
if not hasUse(useKey) then | |||
addUse(useKey) | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end | |||
-- Other odds and ends: | |||
-- Skillcapes are tied to the appropriate skill | |||
-- Except Maximum Skillcape, which is tied to all skills. (And so is the Signet Ring) | |||
-- And combat skillcapes, since combat skills don't get special treatment | |||
if item.tier == 'Skillcape' then | |||
local ignoreCapes = { | |||
'melvorD:Attack_Skillcape', | |||
'melvorD:Strength_Skillcape', | |||
'melvorD:Defence_Skillcape', | |||
'melvorD:Hitpoints_Skillcape', | |||
'melvorF:Ranged_Skillcape', | |||
'melvorTotH:Superior_Attack_Skillcape', | |||
'melvorTotH:Superior_Strength_Skillcape', | |||
'melvorTotH:Superior_Defence_Skillcape', | |||
'melvorTotH:Superior_Hitpoints_Skillcape', | |||
'melvorTotH:Superior_Ranged_Skillcape', | |||
} | |||
local allCapes = { | |||
'melvorF:Max_Skillcape', | |||
'melvorF:Cape_of_Completion', | |||
'melvorTotH:Superior_Max_Skillcape', | |||
'melvorTotH:Superior_Cape_Of_Completion' | |||
} | |||
if Shared.contains(allCapes, item.id) then | |||
addUse('AllSkills') | |||
elseif Shared.contains({'melvorF:Magic_Skillcape', 'melvorTotH:Superior_Magic_Skillcape'}, item.id) then | |||
addUse('melvorD:Magic') | |||
addUse('AltMagic') | |||
elseif not Shared.contains(ignoreCapes, item.id) then | |||
local splitName = Shared.splitString(item.name, ' ') | |||
local skillName = (splitName[1] == 'Superior' and splitName[2]) or splitName[1] | |||
addUse(skillName) | |||
end | |||
table.insert(categoryArray, '[[Category:Skillcapes]]') | |||
end | |||
--Special note for Charge Stone of Rhaelyx | |||
if item.id == 'melvorD:Charge_Stone_of_Rhaelyx' then | |||
addUse('ChargeStone') | |||
end | |||
--Some items are needed to make shop purchases | |||
local shopArray = Shop.getItemCostArray(item.id) | |||
if not Shared.tableIsEmpty(shopArray) then | |||
addUse('Shop') | |||
end | |||
-- Township Tasks | |||
for _, task in ipairs(SkillData.Township.tasks) do | |||
if task.goals.items[1] ~= nil then -- Skip tasks with no items | |||
if GameData.getEntityByID(task.goals.items, item.id) then | |||
addUse('TownshipTask') | |||
break | |||
end | |||
end | |||
end | |||
-- Generate result text | |||
local useArray = {} | |||
local prefix, delim = asList and '* ' or '', asList and '\r\n' or '<br/>' | |||
for skillID, skillName in Shared.spairs(skillUses, function(t, a, b) return t[a] < t[b] end) do | |||
table.insert(useArray, prefix .. Icons.Icon({skillName, type='skill'})) | |||
end | |||
for use, _ in Shared.skpairs(otherUses) do | |||
table.insert(useArray, prefix .. (otherUseText[use] or use)) | |||
end | |||
return table.concat(useArray, delim) .. (addCategories and table.concat(categoryArray, '') or '') | |||
end | end | ||
function p.getItemUses(frame) | function p.getItemUses(frame) | ||
local itemName = frame.args ~= nil and frame.args[1] or frame | |||
local item = Items.getItem(itemName) | |||
local addCategories = false | |||
local asList = true | |||
if frame.args ~= nil then | |||
addCategories = frame.args.addCategories ~= nil and frame.args.addCategories ~= '' and frame.args.addCategories ~= 'false' | |||
asList = frame.args.addCategories == nil or frame.args.addCategories == '' or frame.args.addCategories == 'true' | |||
end | |||
if item == nil then | |||
return Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
return p._getItemUses(item, asList, addCategories) | |||
end | end | ||
function p._getItemUseTable(item) | function p._getItemUseTable(item) | ||
local useArray = {} | |||
-- Loop through all upgrades to find anything that can be upgraded using our source | |||
for i, upgrade in ipairs(GameData.rawData.itemUpgrades) do | |||
for j, itemCost in ipairs(upgrade.itemCosts) do | |||
if itemCost.id == item.id then | |||
local rowReq = nil | |||
-- Potions do have upgrade requirements though | |||
local upgradeItem = Items.getItemByID(upgrade.upgradedItemID) | |||
if upgradeItem ~= nil and upgradeItem.charges ~= nil and upgradeItem.tier ~= nil then | |||
local levelUnlock = GameData.getEntityByProperty(SkillData.Herblore.masteryLevelUnlocks, 'descriptionID', upgradeItem.tier + 1) | |||
if levelUnlock ~= nil then | |||
rowReq = Icons._MasteryReq(upgradeItem.name, levelUnlock.level) | |||
end | |||
end | |||
table.insert(useArray, {item = {id = upgradeItem.id, name = upgradeItem.name}, qty = 1, mats = upgrade.itemCosts, skill = 'Upgrade', req = rowReq, xp = 'N/A', gp = upgrade.gpCost, sc = upgrade.scCost}) | |||
end | |||
end | |||
end | |||
-- Cooking, Smithing, Fletching, Crafting, Runecrafting, Herblore | |||
-- All have somewhat consistent recipe data structures | |||
local recipeSkillIDs = { | |||
'melvorD:Cooking', | |||
'melvorD:Smithing', | |||
'melvorD:Fletching', | |||
'melvorD:Crafting', | |||
'melvorD:Runecrafting', | |||
'melvorD:Herblore' | |||
} | |||
for i, recipeSkillID in ipairs(recipeSkillIDs) do | |||
local skillName = Constants.getSkillName(recipeSkillID) | |||
local _, localSkillID = GameData.getLocalID(recipeSkillID) | |||
-- Iterate over all recipes for the current skill | |||
for j, recipe in ipairs(SkillData[localSkillID].recipes) do | |||
local costLists = {recipe.alternativeCosts or {}, {{["itemCosts"] = recipe.itemCosts}}} | |||
for k, costList in pairs(costLists) do | |||
for m, costDef in pairs(costList) do | |||
for n, itemCost in ipairs(costDef.itemCosts) do | |||
if itemCost.id == item.id then | |||
local recipeItemIDs = nil | |||
if recipeSkillID == 'melvorD:Herblore' then | |||
recipeItemIDs = recipe.potionIDs | |||
elseif recipeSkillID == 'melvorD:Cooking' then | |||
recipeItemIDs = {recipe.productID, recipe.perfectCookID} | |||
else | |||
recipeItemIDs = {recipe.productID} | |||
end | |||
for o, recipeItemID in ipairs(recipeItemIDs) do | |||
local recipeItem = Items.getItemByID(recipeItemID) | |||
if recipeItem ~= nil then | |||
local itemDef = {id = recipe.itemID, name = recipeItem.name} | |||
local qty = (recipe.baseQuantity or 1) * (costDef.quantityMultiplier or 1) | |||
local rowReq = recipe.level | |||
local reqVal = nil | |||
if recipeSkillID == 'melvorD:Herblore' then | |||
-- Herblore may also have a mastery requirement | |||
local levelUnlock = GameData.getEntityByProperty(SkillData.Herblore.masteryLevelUnlocks, 'descriptionID', recipeItem.tier + 1) | |||
if levelUnlock ~= nil and levelUnlock.level > 1 then | |||
local masteryReq = Icons._MasteryReq(recipeItem.name, levelUnlock.level) | |||
reqVal = rowReq + levelUnlock.level * 0.01 | |||
rowReq = Icons._SkillReq(skillName, rowReq) .. '<br/>' .. masteryReq | |||
end | |||
end | |||
table.insert(useArray, {item = itemDef, qty = qty, mats = costDef.itemCosts, gp = recipe.gpCost, sc = recipe.scCost, skill = skillName, reqVal = reqVal, req = rowReq, xp = recipe.baseExperience}) | |||
end | |||
end | |||
break | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end | |||
-- Farming | |||
for i, recipe in ipairs(SkillData.Farming.recipes) do | |||
if recipe.seedCost.id == item.id then | |||
local product = Items.getItemByID(recipe.productId) | |||
local mat = {{id = recipe.seedCost.id, quantity = recipe.seedCost.quantity}} | |||
local rowReq = recipe.level | |||
local category = GameData.getEntityByID(SkillData.Farming.categories, recipe.categoryID) | |||
local qty = 5 * category.harvestMultiplier | |||
local xp = recipe.baseExperience | |||
table.insert(useArray, {item = {id = product.id, name = product.name}, qty = qty, mats = mat, skill = 'Farming', req = rowReq, xp = xp}) | |||
end | |||
end | |||
-- Agility | |||
local obstacles = Agility.getObstaclesForItem(item.id) | |||
for i, obstacle in ipairs(obstacles) do | |||
local itemCosts = {} | |||
for j, itemDef in ipairs(obstacle.itemCosts) do | |||
table.insert(itemCosts, {id = itemDef.id, quantity = itemDef.quantity}) | |||
end | |||
local req = Agility._getObstacleRequirements(obstacle) | |||
--local objType = (obstacle.category == nil and 'Pillar') or 'Obstacle' | |||
table.insert(useArray, {item = {id = obstacle.id, name = obstacle.name}, qty = 1, mats = itemCosts, gp = obstacle.gpCost, sc = obstacle.scCost, skill = 'Agility', req = req, type = 'skill'}) | |||
end | |||
-- Summoning | |||
for i, recipe in ipairs(SkillData.Summoning.recipes) do | |||
local recipeGPCost = SkillData.Summoning.recipeGPCost | |||
local useShards = false | |||
local recipeItem = nil | |||
for j, itemCost in ipairs(recipe.itemCosts) do | |||
if itemCost.id == item.id then | |||
useShards = true | |||
break | |||
end | |||
end | |||
-- Non-shard items | |||
-- Familiar recipes may also have a currency cost without any non-shard | |||
-- items, so account for this with a dummy ID such that one iteration | |||
-- of the below loop always occurs | |||
local nonShardItemIDs = (Shared.tableIsEmpty(recipe.nonShardItemCosts) and {''} or recipe.nonShardItemCosts) | |||
for j, nonShardItemID in ipairs(nonShardItemIDs) do | |||
if useShards or nonShardItemID == item.id then | |||
-- Item is used in this particular synergy recipe | |||
if recipeItem == nil then | |||
recipeItem = Items.getItemByID(recipe.productID) | |||
end | |||
local nonShardItem = Items.getItemByID(nonShardItemID) | |||
local recipeCosts = Shared.clone(recipe.itemCosts) | |||
local recipeCosts = {} | |||
for k, itemCost in ipairs(recipe.itemCosts) do | |||
table.insert(recipeCosts, {id = itemCost.id, quantity = itemCost.quantity}) | |||
end | |||
if nonShardItem ~= nil then | |||
-- Item ID can be nil for recipes such as Leprechaun or Cyclops | |||
local itemValue = math.max(nonShardItem.sellsFor, 20) | |||
local nonShardQty = math.max(1, math.floor(recipeGPCost / itemValue)) | |||
table.insert(recipeCosts, {id = nonShardItemID, quantity = nonShardQty}) | |||
end | |||
table.insert(useArray, {item = {id = recipeItem.id, name = recipeItem.name}, qty = recipe.baseQuantity, mats = recipeCosts, gp = recipe.gpCost, sc = recipe.scCost, skill = 'Summoning', req = recipe.level, xp = recipe.baseExperience}) | |||
end | |||
end | |||
end | |||
--Handle shop purchases using Module:Shop | |||
local shopUses = Shop.getItemCostArray(item.id) | |||
for i, shopUse in ipairs(shopUses) do | |||
local purchase = shopUse.purchase | |||
local rowReq = Shop.getRequirementString(purchase.purchaseRequirements) | |||
local iconType = (purchase.contains.items ~= nil and not Shared.tableIsEmpty(purchase.contains.items) and 'item') or 'upgrade' | |||
local gpCost = Shop.getCurrencyCostString(purchase.cost, 'gp') | |||
local scCost = Shop.getCurrencyCostString(purchase.cost, 'slayerCoins') | |||
local rcCost = Shop.getCurrencyCostString(purchase.cost, 'raidCoins') | |||
table.insert(useArray, {item = {name = Shop._getPurchaseName(purchase)}, qty = 1, mats = purchase.cost.items, skill = 'Shop', req = rowReq, xp = 'N/A', gp = gpCost, sc = scCost, rc = rcCost, type = iconType}) | |||
end | |||
--Finally build the table using what we've learned | |||
table.sort(useArray, function(a, b) | |||
local aReqVal = a.reqVal ~= nil and a.reqVal or a.req | |||
local bReqVal = b.reqVal ~= nil and b.reqVal or b.req | |||
if a.skill ~= b.skill then | |||
return a.skill < b.skill | |||
elseif type(aReqVal) ~= type(bReqVal) then | |||
return tostring(aReqVal) < tostring(bReqVal) | |||
elseif aReqVal ~= bReqVal then | |||
return aReqVal < bReqVal | |||
else | |||
return a.item.name < b.item.name | |||
end | |||
end) | |||
local resultPart = {} | |||
if not Shared.tableIsEmpty(useArray) then | |||
local typeTextList = { | |||
["Shop"] = Icons.Icon({'Shop'}), | |||
["Upgrade"] = '[[Upgrading Items|Upgrade]]' | |||
} | |||
-- Header | |||
table.insert(resultPart, '{| class="wikitable stickyHeader sortable"') | |||
table.insert(resultPart, '\r\n|- class="headerRow-0"') | |||
table.insert(resultPart, '\r\n!colspan=2|Item Created!!Type!!Requirements!!XP!!Ingredients') | |||
-- Rows | |||
for i, row in ipairs(useArray) do | |||
local qty = row.qty ~= nil and row.qty or 1 | |||
local iconType = row.type ~= nil and row.type or 'item' | |||
local iconName = row.item.name | |||
if row.skill == 'Agility' then | |||
iconType = 'agility' | |||
end | |||
local typeName = row.skill ~= nil and row.skill or '' | |||
local typeText = typeTextList[typeName] or Icons.Icon({typeName, type='skill'}) or '' | |||
local reqVal, reqText = row.reqVal, 'None' | |||
if type(row.req) == 'number' then | |||
reqVal = row.req | |||
reqText = Icons._SkillReq(typeName, row.req) | |||
elseif type(row.req) == 'string' then | |||
reqText = row.req | |||
end | |||
local xpVal, xpText = 0, 'N/A' | |||
if type(row.xp) == 'string' then | |||
xpText = row.xp | |||
elseif type(row.xp) == 'number' then | |||
xpVal = row.xp | |||
xpText = Shared.formatnum(row.xp) .. ' ' .. Icons.Icon({typeName, type='skill', notext=true}) .. ' XP' | |||
end | |||
local matRow = {} | |||
if type(row.mats) == 'table' then | |||
for j, itemCost in ipairs(row.mats) do | |||
local matItemID = itemCost.id or itemCost[1] or -1 | |||
local matItem = Items.getItemByID(matItemID) | |||
local matQty = itemCost.quantity or itemCost[2] or 1 | |||
if matItem == nil then | |||
table.insert(matRow, Shared.printError('Failed to find item with ID "' .. itemCost.id .. '"')) | |||
elseif type(matQty) == 'number' then | |||
table.insert(matRow, Icons.Icon({matItem.name, type='item', qty=matQty})) | |||
else | |||
table.insert(matRow, Icons.Icon({matItem.name, type='item'})) | |||
end | |||
end | |||
end | |||
if row.gp ~= nil then | |||
local gpText = nil | |||
if type(row.gp) == 'number' and row.gp > 0 then | |||
gpText = Icons.GP(row.gp) | |||
elseif type(row.gp) == 'string' then | |||
gpText = row.gp | |||
end | |||
table.insert(matRow, gpText) | |||
end | |||
if row.sc ~= nil then | |||
local scText = nil | |||
if type(row.sc) == 'number' and row.sc > 0 then | |||
scText = Icons.SC(row.sc) | |||
elseif type(row.sc) == 'string' then | |||
scText = row.sc | |||
end | |||
table.insert(matRow, scText) | |||
end | |||
if row.rc ~= nil then | |||
local rcText = nil | |||
if type(row.rc) == 'number' and row.rc > 0 then | |||
rcText = Icons.RC(row.rc) | |||
elseif type(row.rc) == 'string' then | |||
rcText = row.rc | |||
end | |||
table.insert(matRow, rcText) | |||
end | |||
-- Item created | |||
table.insert(resultPart, '\r\n|-\r\n|data-sort-value="' .. row.item.name .. '"| ') | |||
table.insert(resultPart, Icons.Icon({iconName, row.item.name, type=iconType, notext=true, size=50})) | |||
table.insert(resultPart, '\r\n| ') | |||
if qty > 1 then | |||
table.insert(resultPart, "'''" .. Shared.formatnum(qty) .. "x''' ") | |||
end | |||
table.insert(resultPart, Icons.Icon({iconName, row.item.name, type=iconType, noicon=true})) | |||
-- Type | |||
table.insert(resultPart, '\r\n|data-sort-value="' .. typeName .. '"| ' .. typeText) | |||
-- Requirements | |||
table.insert(resultPart, '\r\n|style="text-align:right;"') | |||
if row.reqVal ~= nil then | |||
table.insert(resultPart, ' data-sort-value="' .. reqVal .. '"') | |||
end | |||
table.insert(resultPart, '| ' .. reqText) | |||
-- XP | |||
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. xpVal .. '"| ' .. xpText) | |||
-- Ingredients | |||
table.insert(resultPart, '\r\n| ' .. table.concat(matRow, '<br/>')) | |||
end | |||
table.insert(resultPart, '\r\n|}') | |||
end | |||
local spellUseTable = p._getSpellUseTable(item) | |||
if spellUseTable ~= nil and spellUseTable ~= '' then | |||
table.insert(resultPart, '\r\n===' .. Icons.Icon({'Magic', type='skill', size=30}) .. '===\r\n' .. spellUseTable) | |||
end | |||
if Shared.tableIsEmpty(resultPart) then | |||
return '' | |||
else | |||
return '==Uses==\r\n' .. table.concat(resultPart) | |||
end | |||
end | end | ||
function p.getItemUseTable(frame) | function p.getItemUseTable(frame) | ||
local itemName = frame.args ~= nil and frame.args[1] or frame | |||
local item = Items.getItem(itemName) | |||
if item == nil then | |||
return Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
return p._getItemUseTable(item) | |||
end | end | ||
function p._getSpellUseTable(item) | function p._getSpellUseTable(item) | ||
local spellList = Magic.getSpellsUsingItem(item.id, true) | |||
--Bail immediately if no spells are found | |||
if Shared.tableIsEmpty(spellList) then | |||
return '' | |||
end | |||
--Adding a check for if the Items column is needed | |||
local hasItems = false | |||
for i, spell in pairs(spellList) do | |||
if Magic._getSpellItems(spell) ~= '' then | |||
hasItems = true | |||
break | |||
end | |||
end | |||
local resultPart = {} | |||
table.insert(resultPart, '{|class="wikitable sortable"\r\n!colspan="2"|Spell') | |||
table.insert(resultPart, '!!Requirements') | |||
table.insert(resultPart, '!!Type!!style="width:275px"|Description') | |||
table.insert(resultPart, '!!Runes') | |||
if hasItems then | |||
table.insert(resultPart, '!!Item Cost') | |||
end | |||
for i, spell in pairs(spellList) do | |||
local rowPart = {} | |||
table.insert(rowPart, '\r\n|-\r\n|data-sort-value="'..spell.name..'"|') | |||
local iconType = Magic._getSpellIconType(spell) | |||
table.insert(rowPart, Icons.Icon({spell.name, type=iconType, notext=true, size=50})) | |||
table.insert(rowPart, '||'..Icons.Icon({spell.name, type=iconType, noicon=true})) | |||
table.insert(rowPart, '||data-sort-value="'..spell.level..'"|'..Magic._getSpellRequirements(spell)) | |||
table.insert(rowPart, '||data-sort-value="'.. spell.spellBook ..'"|') | |||
table.insert(rowPart, Magic.getSpellTypeLink(spell.spellBook)) | |||
table.insert(rowPart, '||'..Magic._getSpellStat(spell, 'description')) | |||
table.insert(rowPart, '||style="text-align:center"|') | |||
table.insert(rowPart, Magic._getSpellRunes(spell)) | |||
if hasItems then | |||
table.insert(rowPart, '||style="text-align:right"|') | |||
table.insert(rowPart, Magic._getSpellItems(spell)) | |||
end | |||
table.insert(resultPart, table.concat(rowPart)) | |||
end | |||
--Add the table end and add the table to the result string | |||
table.insert(resultPart, '\r\n|}') | |||
return table.concat(resultPart) | |||
end | end | ||
function p.getSpellUseTable(frame) | function p.getSpellUseTable(frame) | ||
local itemName = frame.args ~= nil and frame.args[1] or frame | |||
local item = Items.getItem(itemName) | |||
if item == nil then | |||
return Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
return p._getSpellUseTable(item) | |||
end | |||
--[==[ | |||
-- Uncomment this block and execute 'p.test()' within the debug console | |||
-- to test after making changes | |||
function p.test() | |||
local checkItems = { | |||
'Gold Bar', | |||
'Raw Shrimp', | |||
'Coal Ore', | |||
'Rune Platebody', | |||
'Arrow Shafts', | |||
'Garum Seeds', | |||
'Rune Essence', | |||
'Runite Bar', | |||
'Water Rune', | |||
'Steam Rune', | |||
'Controlled Heat Potion II', | |||
'Wolf', | |||
'Cyclops', | |||
'Leprechaun', | |||
'Redwood Logs', | |||
'Carrot Cake', | |||
'Carrot Cake (Perfect)', | |||
'Mantalyme Herb', | |||
'Carrot', | |||
'Topaz', | |||
'Rune Essence', | |||
'Infernal Claw', | |||
'Chapeau Noir', | |||
'Stardust', | |||
'Rope', | |||
'Ancient Ring of Mastery', | |||
'Mysterious Stone', | |||
'Mastery Token (Cooking)', | |||
'Gem Gloves', | |||
'Basic Bag', | |||
'Bird Nest' | |||
} | |||
local checkFuncs = { | |||
p.getItemUses, | |||
p.getItemUseTable | |||
} | |||
local errCount = 0 | |||
for i, item in ipairs(checkItems) do | |||
local param = {args={item}} | |||
mw.log('=' .. item .. '=') | |||
for j, func in ipairs(checkFuncs) do | |||
local callSuccess, retVal = pcall(func, param) | |||
if not callSuccess then | |||
errCount = errCount + 1 | |||
mw.log('Error with item "' .. item .. '": ' .. retVal) | |||
else | |||
mw.log(retVal) | |||
end | |||
end | |||
end | |||
if errCount == 0 then | |||
mw.log('Test successful') | |||
else | |||
mw.log('Test failed with ' .. errCount .. ' failures') | |||
end | |||
end | end | ||
--]==] | |||
return p | return p |