Module:SkillUnlocks: Difference between revisions

m
Pksage moved page Module:Sandbox/SkillUnlocks to Module:SkillUnlocks without leaving a redirect
No edit summary
m (Pksage moved page Module:Sandbox/SkillUnlocks to Module:SkillUnlocks without leaving a redirect)
 
(22 intermediate revisions by the same user not shown)
Line 1: Line 1:
local p = {}
local p = {}


--This module polls various game data sources to produce a full list of skill
-- This module polls various game data sources to produce a full list of skill
--level unlocks for each skill. The game has a hard-coded set of "milestones"
-- level unlocks for each skill. The game has a hard-coded set of "milestones"
--for each skill that does the same thing, but it is not exhaustive and not
-- for each skill that does the same thing, but it is not exhaustive and not
--permanently visible for most combat skills.
-- permanently visible for most combat skills.
 
-- TODO: Args to filter by level range and unlock type


local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
Line 11: Line 13:
local Items = require('Module:Items')
local Items = require('Module:Items')
local CombatAreas = require('Module:CombatAreas')
local CombatAreas = require('Module:CombatAreas')
local Shop = require('Module:Shop')
local Township = require('Module:Township')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData


local CHECK_ITEMS = {'Attack', 'Strength', 'Defence', 'Ranged', 'Magic',  
-- This excludes certain checks pertinent to all skills, like equipment
'Slayer'}
local SKILL_CHECK_MAP = {
local CHECK_AREAS = {'Slayer'}
['Attack'] = {},
['Strength'] = {},
['Defence'] = {},
['Hitpoints'] = {},
['Ranged'] = {},
['Magic'] = {'spells', 'altmagic'},
['Prayer'] = {'prayers'},
['Slayer'] = {'areas'},
['Farming'] = {'mastery', 'gatheringitems', 'farmingplots'},
['Township'] = {'townshipunlocks'},
['Woodcutting'] = {'mastery', 'gatheringitems'},
['Fishing'] = {'mastery', 'gatheringitems'},
['Firemaking'] = {'mastery', 'firemaking'},
['Cooking'] = {'mastery', 'artisanitems'},
['Mining'] = {'mastery', 'gatheringitems'},
['Smithing'] = {'mastery', 'artisanitems'},
['Thieving'] = {'mastery', 'thieving'},
['Fletching'] = {'mastery', 'artisanitems'},
['Crafting'] = {'mastery', 'artisanitems'},
['Runecrafting'] = {'mastery', 'artisanitems'},
['Herblore'] = {'mastery', 'artisanitems'},
['Agility'] = {'mastery', 'agilityslots'},
['Summoning'] = {'mastery', 'artisanitems'},
['Astrology'] = {'mastery', 'constellations'},
['Alt. Magic'] = {'altmagic'},
}
local TYPE_SORT_ORDER = {
local TYPE_SORT_ORDER = {
['item'] = 1,  
['special'] = 1,
['combatArea'] = 2,
['biome'] = 2,
['slayerArea'] = 3,
['building'] = 3,
['dungeon'] = 4
['plot'] = 4,
['obstacleslot'] = 5,
['pillar'] = 6,
['spell'] = 7,
['prayer'] = 8,
['thieving'] = 9,
['constellation'] = 10,
['gathering'] = 11,
['artisan'] = 12,
['item'] = 13,  
['combatArea'] = 14,
['slayerArea'] = 15,
['dungeon'] = 16,
['shop'] = 17,
['trader'] = 18,
['obstacle'] = 19
}
}
local VERBS_PER_SUBTYPE = {
local VERBS_PER_SUBTYPE = {
Line 27: Line 73:
['Magic Book'] = 'Wield',
['Magic Book'] = 'Wield',
['Ranged Weapon'] = 'Wield',
['Ranged Weapon'] = 'Wield',
['Ammo'] = 'Use',
['Ammo'] = 'Wield',
['Equipment'] = 'Equip',
['Equipment'] = 'Wear',
['Armour'] = 'Equip',
['Armour'] = 'Wear',
['Trimmed Armour'] = 'Equip',
['Trimmed Armour'] = 'Wear',
['Magic Armour'] = 'Equip',
['Magic Armour'] = 'Wear',
['Ranged Armour'] = 'Equip',
['Ranged Armour'] = 'Wear',
['Slayer Armour'] = 'Equip',
['Slayer Armour'] = 'Wear',
['Ring'] = 'Equip',  
['Ring'] = 'Wear',  
['Amulet'] = 'Equip',
['Amulet'] = 'Wear',
['combatArea'] = 'Access',
['combatArea'] = 'Access',
['slayerArea'] = 'Access',
['slayerArea'] = 'Access',
['dungeon'] = 'Access'
['dungeon'] = 'Access',
['standard'] = 'Cast',
['aurora'] = 'Cast',
['curse'] = 'Cast',
['ancient'] = 'Cast',
['archaic'] = 'Cast',
['prayer'] = 'Use',
['altMagic'] = 'Cast',
['tree'] = 'Cut',
['fish'] = 'Catch',
['Essence'] = 'Mine',
['Ore'] = 'Mine',
['Gem'] = 'Mine',
['artisan'] = 'Create',
['melvorD:Fire'] = 'Cook',
['melvorD:Furnace'] = 'Bake',
['melvorD:Pot'] = 'Boil',
['melvorD:Bars'] = 'Smelt',
['melvorF:SkillPotions'] = 'Brew',
['melvorF:CombatPotions'] = 'Brew',
['log'] = 'Burn',
['npc'] = 'Pickpocket',
['constellation'] = 'Study',
['shop'] = 'Purchase',
['plot'] = 'New',
['biome'] = 'Access',
['basicBuilding'] = 'Build',
['trader'] = 'Trade for',
['obstacle'] = 'Build',
['obstacleslot'] = 'Build',
['pillar'] = 'Build'
}
}
local SUBTYPE_OVERRIDES = {
local SUBTYPE_OVERRIDES = {
Line 55: Line 131:
['Spectral Ice Sword'] = 'Weapon',
['Spectral Ice Sword'] = 'Weapon',
['Torrential Blast Crossbow'] = 'Ranged Weapon'
['Torrential Blast Crossbow'] = 'Ranged Weapon'
}
local SUBTYPE_SORT_OVERRIDES = {
['melvorD:Bars'] = '1',
['melvorF:StandardRunes'] = '1',
['log'] = '1'
}
}
local GEAR_SETS = {
local GEAR_SETS = {
Line 62: Line 143:
['level'] = 30,
['level'] = 30,
['entities'] = {'Adamant Boots', '(S) Adamant Boots', '(G) Adamant Boots', 'Adamant Gloves', 'Adamant Helmet', '(S) Adamant Helmet', '(G) Adamant Helmet', 'Adamant Platebody', '(S) Adamant Platebody', '(G) Adamant Platebody', 'Adamant Platelegs', '(S) Adamant Platelegs', '(G) Adamant Platelegs', 'Adamant Shield', '(S) Adamant Shield', '(G) Adamant Shield'}
['entities'] = {'Adamant Boots', '(S) Adamant Boots', '(G) Adamant Boots', 'Adamant Gloves', 'Adamant Helmet', '(S) Adamant Helmet', '(G) Adamant Helmet', 'Adamant Platebody', '(S) Adamant Platebody', '(G) Adamant Platebody', 'Adamant Platelegs', '(S) Adamant Platelegs', '(G) Adamant Platelegs', 'Adamant Shield', '(S) Adamant Shield', '(G) Adamant Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Adamant Ranged Weapons',
['level'] = 30,
['entities'] = {'Adamant Crossbow', 'Adamant Javelin', 'Adamant Throwing Knife'}
},
},
{
{
Line 104: Line 191:
['level'] = 80,
['level'] = 80,
['entities'] = {'Ancient D-hide Body', 'Ancient D-hide Chaps', 'Ancient D-hide Shield', 'Ancient D-hide Vambraces', '(U) Ancient D-hide Body', '(U) Ancient D-hide Chaps', '(U) Ancient D-hide Shield', '(U) Ancient D-hide Vambraces'}
['entities'] = {'Ancient D-hide Body', 'Ancient D-hide Chaps', 'Ancient D-hide Shield', 'Ancient D-hide Vambraces', '(U) Ancient D-hide Body', '(U) Ancient D-hide Chaps', '(U) Ancient D-hide Shield', '(U) Ancient D-hide Vambraces'}
},
{
['verb'] = 'Wield',
['name'] = 'Ancient Ranged Weapons',
['level'] = 70,
['entities'] = {'Ancient Crossbow', 'Ancient Javelin', 'Ancient Throwing Knife', 'Ancient Longbow'}
},
},
{
{
Line 122: Line 215:
['level'] = 105,
['level'] = 105,
['entities'] = {'Augite Boots', '(I) Augite Boots', '(P) Augite Boots', 'Augite Gloves', 'Augite Helmet', '(I) Augite Helmet', '(P) Augite Helmet', 'Augite Platebody', '(I) Augite Platebody', '(P) Augite Platebody', 'Augite Platelegs', '(I) Augite Platelegs', '(P) Augite Platelegs', 'Augite Shield', '(I) Augite Shield', '(P) Augite Shield'}
['entities'] = {'Augite Boots', '(I) Augite Boots', '(P) Augite Boots', 'Augite Gloves', 'Augite Helmet', '(I) Augite Helmet', '(P) Augite Helmet', 'Augite Platebody', '(I) Augite Platebody', '(P) Augite Platebody', 'Augite Platelegs', '(I) Augite Platelegs', '(P) Augite Platelegs', 'Augite Shield', '(I) Augite Shield', '(P) Augite Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Augite Ranged Weapons',
['level'] = 105,
['entities'] = {'Augite Crossbow', 'Augite Javelin', 'Augite Throwing Knife'}
},
},
{
{
Line 128: Line 227:
['level'] = 105,
['level'] = 105,
['entities'] = {'Augite 2H Sword', 'Augite Battleaxe', 'Augite Dagger', 'Augite Scimitar', 'Augite Sword'}
['entities'] = {'Augite 2H Sword', 'Augite Battleaxe', 'Augite Dagger', 'Augite Scimitar', 'Augite Sword'}
},
{
['verb'] = 'Wield',
['name'] = 'Battlestaves',
['level'] = 30,
['entities'] = {'Air Battlestaff', 'Earth Battlestaff', 'Fire Battlestaff', 'Water Battlestaff'}
},
},
{
{
Line 170: Line 275:
['level'] = 1,
['level'] = 1,
['entities'] = {'Bronze Boots', '(S) Bronze Boots', '(G) Bronze Boots', 'Bronze Gloves', 'Bronze Helmet', '(S) Bronze Helmet', '(G) Bronze Helmet', 'Bronze Platebody', '(S) Bronze Platebody', '(G) Bronze Platebody', 'Bronze Platelegs', '(S) Bronze Platelegs', '(G) Bronze Platelegs', 'Bronze Shield', '(S) Bronze Shield', '(G) Bronze Shield'}
['entities'] = {'Bronze Boots', '(S) Bronze Boots', '(G) Bronze Boots', 'Bronze Gloves', 'Bronze Helmet', '(S) Bronze Helmet', '(G) Bronze Helmet', 'Bronze Platebody', '(S) Bronze Platebody', '(G) Bronze Platebody', 'Bronze Platelegs', '(S) Bronze Platelegs', '(G) Bronze Platelegs', 'Bronze Shield', '(S) Bronze Shield', '(G) Bronze Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Bronze Ranged Weapons',
['level'] = 1,
['entities'] = {'Bronze Crossbow', 'Bronze Javelin', 'Bronze Throwing Knife'}
},
},
{
{
Line 182: Line 293:
['level'] = 110,
['level'] = 110,
['entities'] = {'Carrion Body', 'Carrion Chaps', 'Carrion Shield', 'Carrion Vambraces', '(U) Carrion Body', '(U) Carrion Chaps', '(U) Carrion Shield', '(U) Carrion Vambraces'}
['entities'] = {'Carrion Body', 'Carrion Chaps', 'Carrion Shield', 'Carrion Vambraces', '(U) Carrion Body', '(U) Carrion Chaps', '(U) Carrion Shield', '(U) Carrion Vambraces'}
},
{
['verb'] = 'Wield',
['name'] = 'Carrion Bows',
['level'] = 110,
['entities'] = {'Carrion Longbow', 'Carrion Shortbow'}
},
},
{
{
Line 188: Line 305:
['level'] = 100,
['level'] = 100,
['entities'] = {'Corundum Boots', '(I) Corundum Boots', '(P) Corundum Boots', 'Corundum Gloves', 'Corundum Helmet', '(I) Corundum Helmet', '(P) Corundum Helmet', 'Corundum Platebody', '(I) Corundum Platebody', '(P) Corundum Platebody', 'Corundum Platelegs', '(I) Corundum Platelegs', '(P) Corundum Platelegs', 'Corundum Shield', '(I) Corundum Shield', '(P) Corundum Shield'}
['entities'] = {'Corundum Boots', '(I) Corundum Boots', '(P) Corundum Boots', 'Corundum Gloves', 'Corundum Helmet', '(I) Corundum Helmet', '(P) Corundum Helmet', 'Corundum Platebody', '(I) Corundum Platebody', '(P) Corundum Platebody', 'Corundum Platelegs', '(I) Corundum Platelegs', '(P) Corundum Platelegs', 'Corundum Shield', '(I) Corundum Shield', '(P) Corundum Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Corundum Ranged Weapons',
['level'] = 100,
['entities'] = {'Corundum Crossbow', 'Corundum Javelin', 'Corundum Throwing Knife'}
},
},
{
{
Line 200: Line 323:
['level'] = 110,
['level'] = 110,
['entities'] = {'Divine Boots', '(I) Divine Boots', '(P) Divine Boots', 'Divine Gloves', 'Divine Helmet', '(I) Divine Helmet', '(P) Divine Helmet', 'Divine Platebody', '(I) Divine Platebody', '(P) Divine Platebody', 'Divine Platelegs', '(I) Divine Platelegs', '(P) Divine Platelegs', 'Divine Shield', '(I) Divine Shield', '(P) Divine Shield'}
['entities'] = {'Divine Boots', '(I) Divine Boots', '(P) Divine Boots', 'Divine Gloves', 'Divine Helmet', '(I) Divine Helmet', '(P) Divine Helmet', 'Divine Platebody', '(I) Divine Platebody', '(P) Divine Platebody', 'Divine Platelegs', '(I) Divine Platelegs', '(P) Divine Platelegs', 'Divine Shield', '(I) Divine Shield', '(P) Divine Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Divine Ranged Weapons',
['level'] = 110,
['entities'] = {'Divine Crossbow', 'Divine Javelin', 'Divine Throwing Knife'}
},
},
{
{
Line 212: Line 341:
['level'] = 60,
['level'] = 60,
['entities'] = {'Dragon Boots', '(S) Dragon Boots', '(G) Dragon Boots', 'Dragon Gloves', 'Dragon Helmet', '(S) Dragon Helmet', '(G) Dragon Helmet', 'Dragon Platebody', '(S) Dragon Platebody', '(G) Dragon Platebody', 'Dragon Platelegs', '(S) Dragon Platelegs', '(G) Dragon Platelegs', 'Dragon Shield', '(S) Dragon Shield', '(G) Dragon Shield'}
['entities'] = {'Dragon Boots', '(S) Dragon Boots', '(G) Dragon Boots', 'Dragon Gloves', 'Dragon Helmet', '(S) Dragon Helmet', '(G) Dragon Helmet', 'Dragon Platebody', '(S) Dragon Platebody', '(G) Dragon Platebody', 'Dragon Platelegs', '(S) Dragon Platelegs', '(G) Dragon Platelegs', 'Dragon Shield', '(S) Dragon Shield', '(G) Dragon Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Dragon Ranged Weapons',
['level'] = 60,
['entities'] = {'Dragon Crossbow', 'Dragon Javelin', 'Dragon Throwing Knife'}
},
},
{
{
Line 242: Line 377:
['level'] = 100,
['level'] = 100,
['entities'] = {'Elderwood Body', 'Elderwood Chaps', 'Elderwood Shield', 'Elderwood Vambraces', '(U) Elderwood Body', '(U) Elderwood Chaps', '(U) Elderwood Shield', '(U) Elderwood Vambraces'}
['entities'] = {'Elderwood Body', 'Elderwood Chaps', 'Elderwood Shield', 'Elderwood Vambraces', '(U) Elderwood Body', '(U) Elderwood Chaps', '(U) Elderwood Shield', '(U) Elderwood Vambraces'}
},
{
['verb'] = 'Wield',
['name'] = 'Elderwood Bows',
['level'] = 100,
['entities'] = {'Elderwood Longbow', 'Elderwood Shortbow'}
},
},
{
{
Line 296: Line 437:
['level'] = 40,
['level'] = 40,
['entities'] = {'Ice Boots', 'Ice Helmet', 'Ice Platebody', 'Ice Platelegs', 'Ice Shield'}
['entities'] = {'Ice Boots', 'Ice Helmet', 'Ice Platebody', 'Ice Platelegs', 'Ice Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Ice Bows',
['level'] = 40,
['entities'] = {'Ice Longbow', 'Ice Shortbow'}
},
},
{
{
Line 332: Line 479:
['level'] = 1,
['level'] = 1,
['entities'] = {'Iron Boots', '(S) Iron Boots', '(G) Iron Boots', 'Iron Gloves', 'Iron Helmet', '(S) Iron Helmet', '(G) Iron Helmet', 'Iron Platebody', '(S) Iron Platebody', '(G) Iron Platebody', 'Iron Platelegs', '(S) Iron Platelegs', '(G) Iron Platelegs', 'Iron Shield', '(S) Iron Shield', '(G) Iron Shield'}
['entities'] = {'Iron Boots', '(S) Iron Boots', '(G) Iron Boots', 'Iron Gloves', 'Iron Helmet', '(S) Iron Helmet', '(G) Iron Helmet', 'Iron Platebody', '(S) Iron Platebody', '(G) Iron Platebody', 'Iron Platelegs', '(S) Iron Platelegs', '(G) Iron Platelegs', 'Iron Shield', '(S) Iron Shield', '(G) Iron Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Iron Ranged Weapons',
['level'] = 1,
['entities'] = {'Iron Crossbow', 'Iron Javelin', 'Iron Throwing Knife'}
},
},
{
{
Line 362: Line 515:
['level'] = 110,
['level'] = 110,
['entities'] = {'Lightning Mythical Wizard Boots', 'Lightning Mythical Wizard Bottoms', 'Lightning Mythical Wizard Hat', 'Lightning Mythical Wizard Robes'}
['entities'] = {'Lightning Mythical Wizard Boots', 'Lightning Mythical Wizard Bottoms', 'Lightning Mythical Wizard Hat', 'Lightning Mythical Wizard Robes'}
},
{
['verb'] = 'Wield',
['name'] = 'Magic Bows',
['level'] = 50,
['entities'] = {'Magic Longbow', 'Magic Shortbow'}
},
{
['verb'] = 'Wield',
['name'] = 'Maple Bows',
['level'] = 30,
['entities'] = {'Maple Longbow', 'Maple Shortbow'}
},
},
{
{
Line 368: Line 533:
['level'] = 108,
['level'] = 108,
['entities'] = {'Meteorite Helmet', 'Meteorite Platebody', 'Meteorite Platelegs'}
['entities'] = {'Meteorite Helmet', 'Meteorite Platebody', 'Meteorite Platelegs'}
},
{
['verb'] = 'Wield',
['name'] = 'Meteorite Ranged Weapons',
['level'] = 1,
['entities'] = {'Meteorite Crossbow', 'Meteorite Javelin'}
},
},
{
{
Line 380: Line 551:
['level'] = 20,
['level'] = 20,
['entities'] = {'Mithril Boots', '(S) Mithril Boots', '(G) Mithril Boots', 'Mithril Gloves', 'Mithril Helmet', '(S) Mithril Helmet', '(G) Mithril Helmet', 'Mithril Platebody', '(S) Mithril Platebody', '(G) Mithril Platebody', 'Mithril Platelegs', '(S) Mithril Platelegs', '(G) Mithril Platelegs', 'Mithril Shield', '(S) Mithril Shield', '(G) Mithril Shield'}
['entities'] = {'Mithril Boots', '(S) Mithril Boots', '(G) Mithril Boots', 'Mithril Gloves', 'Mithril Helmet', '(S) Mithril Helmet', '(G) Mithril Helmet', 'Mithril Platebody', '(S) Mithril Platebody', '(G) Mithril Platebody', 'Mithril Platelegs', '(S) Mithril Platelegs', '(G) Mithril Platelegs', 'Mithril Shield', '(S) Mithril Shield', '(G) Mithril Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Mithril Ranged Weapons',
['level'] = 20,
['entities'] = {'Mithril Crossbow', 'Mithril Javelin', 'Mithril Throwing Knife'}
},
},
{
{
Line 392: Line 569:
['level'] = 40,
['level'] = 40,
['entities'] = {'Mystic Air Staff', 'Mystic Earth Staff', 'Mystic Fire Staff', 'Mystic Water Staff'}
['entities'] = {'Mystic Air Staff', 'Mystic Earth Staff', 'Mystic Fire Staff', 'Mystic Water Staff'}
},
{
['verb'] = 'Wield',
['name'] = 'Normal Bows',
['level'] = 1,
['entities'] = {'Normal Longbow', 'Normal Shortbow'}
},
{
['verb'] = 'Wield',
['name'] = 'Oak Bows',
['level'] = 5,
['entities'] = {'Oak Longbow', 'Oak Shortbow'}
},
},
{
{
Line 428: Line 617:
['level'] = 30,
['level'] = 30,
['entities'] = {'Red Wizard Boots', 'Red Wizard Bottoms', 'Red Wizard Hat', 'Red Wizard Robes'}
['entities'] = {'Red Wizard Boots', 'Red Wizard Bottoms', 'Red Wizard Hat', 'Red Wizard Robes'}
},
{
['verb'] = 'Wield',
['name'] = 'Redwood Bows',
['level'] = 60,
['entities'] = {'Redwood Longbow', 'Redwood Shortbow'}
},
},
{
{
Line 434: Line 629:
['level'] = 105,
['level'] = 105,
['entities'] = {'Revenant Body', 'Revenant Chaps', 'Revenant Shield', 'Revenant Vambraces', '(U) Revenant Body', '(U) Revenant Chaps', '(U) Revenant Shield', '(U) Revenant Vambraces'}
['entities'] = {'Revenant Body', 'Revenant Chaps', 'Revenant Shield', 'Revenant Vambraces', '(U) Revenant Body', '(U) Revenant Chaps', '(U) Revenant Shield', '(U) Revenant Vambraces'}
},
{
['verb'] = 'Wield',
['name'] = 'Revenant Bows',
['level'] = 105,
['entities'] = {'Revenant Longbow', 'Revenant Shortbow'}
},
},
{
{
Line 440: Line 641:
['level'] = 40,
['level'] = 40,
['entities'] = {'Rune Boots', '(S) Rune Boots', '(G) Rune Boots', 'Rune Gloves', 'Rune Helmet', '(S) Rune Helmet', '(G) Rune Helmet', 'Rune Platebody', '(S) Rune Platebody', '(G) Rune Platebody', 'Rune Platelegs', '(S) Rune Platelegs', '(G) Rune Platelegs', 'Rune Shield', '(S) Rune Shield', '(G) Rune Shield'}
['entities'] = {'Rune Boots', '(S) Rune Boots', '(G) Rune Boots', 'Rune Gloves', 'Rune Helmet', '(S) Rune Helmet', '(G) Rune Helmet', 'Rune Platebody', '(S) Rune Platebody', '(G) Rune Platebody', 'Rune Platelegs', '(S) Rune Platelegs', '(G) Rune Platelegs', 'Rune Shield', '(S) Rune Shield', '(G) Rune Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Rune Ranged Weapons',
['level'] = 40,
['entities'] = {'Rune Crossbow', 'Rune Javelin', 'Rune Throwing Knife'}
},
},
{
{
Line 446: Line 653:
['level'] = 40,
['level'] = 40,
['entities'] = {'Rune 2H Sword', 'Rune Battleaxe', 'Rune Dagger', 'Rune Scimitar', 'Rune Sword'}
['entities'] = {'Rune 2H Sword', 'Rune Battleaxe', 'Rune Dagger', 'Rune Scimitar', 'Rune Sword'}
},
{
['verb'] = 'Wear',
['name'] = 'Melee Slayer Gear (Basic)',
['level'] = 1,
['entities'] = {'Slayer Helmet (Basic)', 'Slayer Platebody (Basic)'}
},
{
['verb'] = 'Wear',
['name'] = 'Melee Slayer Gear (Strong)',
['level'] = 30,
['entities'] = {'Slayer Helmet (Strong)', 'Slayer Platebody (Strong)'}
},
{
['verb'] = 'Wear',
['name'] = 'Melee Slayer Gear (Elite)',
['level'] = 60,
['entities'] = {'Slayer Helmet (Elite)', 'Slayer Platebody (Elite)'}
},
{
['verb'] = 'Wear',
['name'] = 'Melee Slayer Gear (Master)',
['level'] = 80,
['entities'] = {'Slayer Helmet (Master)', 'Slayer Platebody (Master)'}
},
{
['verb'] = 'Wear',
['name'] = 'Melee Slayer Gear (Legendary)',
['level'] = 100,
['entities'] = {'Slayer Helmet (Legendary)', 'Slayer Platebody (Legendary)'}
},
{
['verb'] = 'Wear',
['name'] = 'Melee Slayer Gear (Mythical)',
['level'] = 110,
['entities'] = {'Slayer Helmet (Mythical)', 'Slayer Platebody (Mythical)'}
},
{
['verb'] = 'Wear',
['name'] = 'Ranged Slayer Gear (Strong)',
['level'] = 30,
['entities'] = {'Slayer Cowl (Strong)', 'Slayer Leather Body (Strong)'}
},
{
['verb'] = 'Wear',
['name'] = 'Ranged Slayer Gear (Elite)',
['level'] = 60,
['entities'] = {'Slayer Cowl (Elite)', 'Slayer Leather Body (Elite)'}
},
{
['verb'] = 'Wear',
['name'] = 'Ranged Slayer Gear (Master)',
['level'] = 80,
['entities'] = {'Slayer Cowl (Master)', 'Slayer Leather Body (Master)'}
},
{
['verb'] = 'Wear',
['name'] = 'Ranged Slayer Gear (Legendary)',
['level'] = 100,
['entities'] = {'Slayer Cowl (Legendary)', 'Slayer Leather Body (Legendary)'}
},
{
['verb'] = 'Wear',
['name'] = 'Ranged Slayer Gear (Mythical)',
['level'] = 110,
['entities'] = {'Slayer Cowl (Mythical)', 'Slayer Leather Body (Mythical)'}
},
{
['verb'] = 'Wear',
['name'] = 'Magic Slayer Gear (Strong)',
['level'] = 30,
['entities'] = {'Slayer Wizard Hat (Strong)', 'Slayer Wizard Robes (Strong)'}
},
{
['verb'] = 'Wear',
['name'] = 'Magic Slayer Gear (Elite)',
['level'] = 60,
['entities'] = {'Slayer Wizard Hat (Elite)', 'Slayer Wizard Robes (Elite)'}
},
{
['verb'] = 'Wear',
['name'] = 'Magic Slayer Gear (Master)',
['level'] = 80,
['entities'] = {'Slayer Wizard Hat (Master)', 'Slayer Wizard Robes (Master)'}
},
{
['verb'] = 'Wear',
['name'] = 'Magic Slayer Gear (Legendary)',
['level'] = 100,
['entities'] = {'Slayer Wizard Hat (Legendary)', 'Slayer Wizard Robes (Legendary)'}
},
{
['verb'] = 'Wear',
['name'] = 'Magic Slayer Gear (Mythical)',
['level'] = 110,
['entities'] = {'Slayer Wizard Hat (Mythical)', 'Slayer Wizard Robes (Mythical)'}
},
},
{
{
Line 458: Line 761:
['level'] = 5,
['level'] = 5,
['entities'] = {'Steel Boots', '(S) Steel Boots', '(G) Steel Boots', 'Steel Gloves', 'Steel Helmet', '(S) Steel Helmet', '(G) Steel Helmet', 'Steel Platebody', '(S) Steel Platebody', '(G) Steel Platebody', 'Steel Platelegs', '(S) Steel Platelegs', '(G) Steel Platelegs', 'Steel Shield', '(S) Steel Shield', '(G) Steel Shield'}
['entities'] = {'Steel Boots', '(S) Steel Boots', '(G) Steel Boots', 'Steel Gloves', 'Steel Helmet', '(S) Steel Helmet', '(G) Steel Helmet', 'Steel Platebody', '(S) Steel Platebody', '(G) Steel Platebody', 'Steel Platelegs', '(S) Steel Platelegs', '(G) Steel Platelegs', 'Steel Shield', '(S) Steel Shield', '(G) Steel Shield'}
},
{
['verb'] = 'Wield',
['name'] = 'Steel Ranged Weapons',
['level'] = 5,
['entities'] = {'Steel Crossbow', 'Steel Javelin', 'Steel Throwing Knife'}
},
},
{
{
Line 482: Line 791:
['level'] = 120,
['level'] = 120,
['entities'] = {'Vorloran Protector Boots', 'Vorloran Protector Gauntlets', 'Vorloran Protector Helmet', 'Vorloran Protector Platebody', 'Vorloran Protector Platelegs'}
['entities'] = {'Vorloran Protector Boots', 'Vorloran Protector Gauntlets', 'Vorloran Protector Helmet', 'Vorloran Protector Platebody', 'Vorloran Protector Platelegs'}
},
{
['verb'] = 'Wear',
['name'] = 'Vorloran Watcher Armour',
['level'] = 120,
['entities'] = {'Vorloran Watcher Boots', 'Vorloran Watcher Gauntlets', 'Vorloran Watcher Helmet', 'Vorloran Watcher Platebody', 'Vorloran Watcher Platelegs'}
},
},
{
{
Line 500: Line 815:
['level'] = 69,
['level'] = 69,
['entities'] = {'Water Expert Wizard Boots', 'Water Expert Wizard Bottoms', 'Water Expert Wizard Hat', 'Water Expert Wizard Robes'}
['entities'] = {'Water Expert Wizard Boots', 'Water Expert Wizard Bottoms', 'Water Expert Wizard Hat', 'Water Expert Wizard Robes'}
},
{
['verb'] = 'Wield',
['name'] = 'Willow Bows',
['level'] = 20,
['entities'] = {'Willow Longbow', 'Willow Shortbow'}
},
{
['verb'] = 'Wield',
['name'] = 'Yew Bows',
['level'] = 40,
['entities'] = {'Yew Longbow', 'Yew Shortbow'}
},
{
['verb'] = 'Purchase',
['name'] = 'Skill Hats',
['level'] = 10,
['entities'] = {'Blacksmiths Hat', 'Burning Mans Hat', 'Crafters Hat', 'Fishermans Hat', 'Fletchers Hat', 'Miners Hat', 'Performance Enhancing Hat', 'Potion Makers Hat', 'Runecrafters Hat', 'Star Gazing Hat', 'Woodcutters Hat'}
},
{
['verb'] = 'Purchase',
['name'] = 'Skill Bodies',
['level'] = 20,
['entities'] = {'Blacksmiths Body', 'Burning Mans Body', 'Crafters Body', 'Fishermans Body', 'Fletchers Body', 'Miners Body', 'Performance Enhancing Body', 'Potion Makers Body', 'Runecrafters Body', 'Star Gazing Body', 'Woodcutters Body'}
},
{
['verb'] = 'Purchase',
['name'] = 'Skill Leggings',
['level'] = 40,
['entities'] = {'Blacksmiths Leggings', 'Burning Mans Leggings', 'Crafters Leggings', 'Fishermans Leggings', 'Fletchers Leggings', 'Miners Leggings', 'Performance Enhancing Leggings', 'Potion Makers Leggings', 'Runecrafters Leggings', 'Star Gazing Leggings', 'Woodcutters Leggings'}
},
{
['verb'] = 'Purchase',
['name'] = 'Skill Boots',
['level'] = 60,
['entities'] = {'Blacksmiths Boots', 'Burning Mans Boots', 'Crafters Boots', 'Fishermans Boots', 'Fletchers Boots', 'Miners Boots', 'Performance Enhancing Boots', 'Potion Makers Boots', 'Runecrafters Boots', 'Star Gazing Boots', 'Woodcutters Boots'}
}
}
}
}
Line 509: Line 860:
end
end
return entityType
return entityType
end
function p._getOtherSkillReqs(reqList, skillName)
-- Remove the current skill's requirement, leaving us with all others
local otherReqs = {}
for i, req in ipairs(reqList) do
if req.type ~= 'SkillLevel' or (req.skillID ~= Constants.getSkillID(skillName) and req.level ~= 1) then
table.insert(otherReqs, req)
end
end
return otherReqs
end
function p._getSpellReqs(spell)
-- Get spell requirements that aren't SkillLevel (ex. equipped item)
local reqs = {}
if spell.requiredItemID ~= nil then
        local item = Items.getItemByID(spell.requiredItemID)
        if item ~= nil then
            table.insert(reqs, {['type'] = 'item', ['item'] = item})
        end
end
if spell.requirements ~= nil then
for i, req in ipairs(spell.requirements) do
table.insert(reqs, req)
end
end
return reqs
end
function p._getGatherableReqs(node, skillName)
-- Get gatherable requirements that aren't SkillLevel (ex. shop item)
local reqs = {}
if node.shopItemPurchased ~= nil then
local purchase = GameData.getEntityByID('shopPurchases', node.shopItemPurchased)
if purchase ~= nil then
table.insert(reqs, {['type'] = 'shop', ['purchase'] = purchase})
end
end
if node.totalMasteryRequired ~= nil then
table.insert(reqs, {['type'] = 'totalMastery', ['mastery'] = node.totalMasteryRequired, ['skill'] = skillName})
end
return reqs
end
function p._addEntities(frame)
local args = frame.args ~= nil and frame.args or frame
local entityList = args[1]
local data = args[2]
local entityType = args.type
local typeParam = args.typeParam
local subType = args.subType
local subTypeParam = args.subTypeParam
local otherReqsFunc = args.otherReqsFunc
for i, entity in ipairs(data) do
local processed = {}
processed.entityName = entity.name
processed.entityType = p._getEntityTrueSubtype(typeParam ~= nil and entity[typeParam] or entityType)
processed.subType = subTypeParam ~= nil and entity[subTypeParam] or subType
processed.skillLevel = entity.level
processed.otherReqs = otherReqsFunc ~= nil and otherReqsFunc(entity) or {}
table.insert(entityList, processed)
end
return entityList
end
end


Line 522: Line 946:
end)
end)
-- TODO: This can probably be made into a generic function for each entity
for i, item in ipairs(itemList) do
for i, item in ipairs(itemList) do
local processed = {}
local processed = {}
Line 530: Line 953:
processed.subType = p._getEntityTrueSubtype(item.type, item.name)
processed.subType = p._getEntityTrueSubtype(item.type, item.name)
processed.skillLevel = Items._getItemStat(item, skillReqLabel)
processed.skillLevel = Items._getItemStat(item, skillReqLabel)
processed.otherReqs = p._getOtherSkillReqs(item.equipRequirements, skillName)
table.insert(entityList, processed)
table.insert(entityList, processed)
end
end
Line 550: Line 974:
for i, area in ipairs(areaList) do
for i, area in ipairs(areaList) do
local processed = {}
local processed = {}
processed.entity = area
processed.entityName = area.name
processed.entityName = area.name
processed.entityType = area.type
processed.entityType = area.type
Line 559: Line 982:
end
end
end
end
processed.otherReqs = p._getOtherSkillReqs(area.entryRequirements, skillName)
table.insert(entityList, processed)
end
return entityList
end
function p._addShopPurchasesWithSkillRequirements(entityList, skillName)
local purchaseList = Shop.getPurchases(function(purchase)
local hasSkillReq = false
for i, req in ipairs(purchase.purchaseRequirements) do
if req.type == 'SkillLevel' and req.skillID == Constants.getSkillID(skillName) then
hasSkillReq = true
end
end
return hasSkillReq
end)
for i, purchase in ipairs(purchaseList) do
-- Skip skillcapes here, as we handle them with items
if purchase.category ~= 'melvorD:Skillcapes' and purchase.category ~= 'melvorTotH:SuperiorSkillcapes' then
local processed = {}
processed.entity = purchase
processed.entityName = Shop._getPurchaseName(purchase)
processed.entityType = 'shop'
processed.subType = Shop._getPurchaseType(purchase)
for a, req in ipairs(purchase.purchaseRequirements) do
if req.type == 'SkillLevel' and req.skillID == Constants.getSkillID(skillName) then
processed.skillLevel = req.level
end
end
processed.otherReqs = p._getOtherSkillReqs(purchase.purchaseRequirements, skillName)
table.insert(entityList, processed)
end
end
return entityList
end
function p._addTraderItemsWithSkillRequirements(entityList, skillName)
-- Iterate over each tradable resource, then each item you can get with it
for i, tsResource in ipairs(Township.Township.itemConversions.fromTownship) do
for j, tsPurchase in ipairs(tsResource.items) do
-- Does this purchase require the current skill?
local hasCurrentSkill = false
local currentSkillLevel = 0
for k, req in ipairs(tsPurchase.unlockRequirements) do
if req.type == 'SkillLevel' and req.skillID == Constants.getSkillID(skillName) then
hasCurrentSkill = true
currentSkillLevel = req.level
end
end
if hasCurrentSkill then
local item = Items.getItemByID(tsPurchase.itemID)
local processed = {}
processed.entity = item
processed.entityName = item.name
processed.entityType = 'trader'
processed.subType = 'trader'
processed.skillLevel = currentSkillLevel
processed.otherReqs = p._getOtherSkillReqs(tsPurchase.unlockRequirements, skillName)
table.insert(entityList, processed)
end
end
end
return entityList
end
function p._addAgilityObstaclesWithSkillRequirements(entityList, skillName)
for i, obstacle in ipairs(SkillData.Agility.obstacles) do
for j, req in ipairs(obstacle.skillRequirements) do
-- Does this obstacle require the current skill?
local hasCurrentSkill = false
local currentSkillLevel = 0
if req.type == 'SkillLevel' and req.skillID == Constants.getSkillID(skillName) then
hasCurrentSkill = true
currentSkillLevel = req.level
end
if hasCurrentSkill then
local processed = {}
processed.entity = obstacle
processed.entityName = obstacle.name
processed.entityType = 'obstacle'
-- Category is zero-indexed
processed.subType = 'Obstacle ' .. tostring(obstacle.category + 1)
processed.skillLevel = currentSkillLevel
processed.otherReqs = p._getOtherSkillReqs(obstacle.skillRequirements, skillName)
table.insert(entityList, processed)
end
end
end
return entityList
end
function p._addSpells(entityList, skillName)
-- Alt. Magic is in a separate function
local SPELL_TYPES = {'standardSpells', 'auroraSpells', 'curseSpells', 'ancientSpells', 'archaicSpells'}
-- Iterate through each spell type and each spell within that type
for i, spellType in ipairs(SPELL_TYPES) do
entityList = p._addEntities({entityList, GameData.rawData[spellType], type='spell', subTypeParam='spellBook', otherReqsFunc=p._getSpellReqs})
end
return entityList
end
function p._addAltMagic(entityList, skillName)
entityList = p._addEntities({entityList, GameData.getSkillData('melvorD:Magic')['altSpells'], type='spell', subType='altMagic', otherReqsFunc=p._getSpellReqs})
return entityList
end
function p._addPrayers(entityList, skillName)
entityList = p._addEntities({entityList, GameData.rawData.prayers, type='prayer', subType='prayer'})
return entityList
end
function p._addFiremakingActions(entityList, skillName)
for i, fireLog in ipairs(SkillData.Firemaking.logs) do
local processed = {}
local logItem = Items.getItemByID(fireLog.logID)
processed.entityName = logItem.name
processed.entityType = 'item'
processed.subType = 'log'
processed.skillLevel = fireLog.level
processed.otherReqs = {}
table.insert(entityList, processed)
table.insert(entityList, processed)
end
end
Line 565: Line 1,118:
end
end


function p._prepareSingleEntity(entity)
function p._addThievingTargets(entityList, skillName)
entityList = p._addEntities({entityList, SkillData.Thieving.npcs, type='thieving', subType='npc'})
return entityList
end
 
function p._addConstellations(entityList, skillName)
entityList = p._addEntities({entityList, SkillData.Astrology.recipes, type='constellation', subType='constellation'})
return entityList
end
 
function p._addFarmingPlots(entityList, skillName)
for i, plot in ipairs(SkillData.Farming.plots) do
local plotName = 'Unknown Plot'
if plot.categoryID == 'melvorD:Allotment' then
plotName = 'Allotment Plot'
elseif plot.categoryID == 'melvorD:Herb' then
plotName = 'Herb Plot'
elseif plot.categoryID == 'melvorD:Tree' then
plotName = 'Tree Plot'
end
local processed = {}
processed.entityName = plotName
processed.entityType = 'plot'
processed.subType = plot.categoryID
processed.skillLevel = plot.level
processed.otherReqs = {}
table.insert(entityList, processed)
end
return entityList
end
 
function p._addTownshipUnlocks(entityList, skillName)
-- This one is weird, because some of the data uses tiers and not levels
-- Add all of the biomes
for i, biome in ipairs(Township.Township.biomes) do
local tierReqs = Township._getTierRequirements(biome.tier)
local processed = {}
processed.entityName = biome.name
processed.entityType = 'biome'
processed.subType = 'biome'
processed.skillLevel = tierReqs.level
processed.otherReqs = {['population'] = tierReqs.population}
table.insert(entityList, processed)
end
-- Add all of the buildings
for i, building in ipairs(Township.Township.buildings) do
local tierReqs = Township._getTierRequirements(building.tier)
local processed = {}
processed.entityName = building.name == 'Statues' and 'Statue of Worship' or building.name
processed.entityType = 'building'
processed.subType = building.upgradesFrom ~= nil and 'upgradedBuilding' or 'basicBuilding'
processed.upgradesFrom = Township._getBuildingDowngrade(building)
processed.skillLevel = tierReqs.level
processed.otherReqs = {['population'] = tierReqs.population}
table.insert(entityList, processed)
end
-- Add the fact that health starts decreasing at level 15
local specialHealth = {
['entityType'] = 'special',
['subType'] = 'special',
['skillLevel'] = 15,
['overrideText'] = 'Township health has a 25% chance to decrease by 1% per update'
}
table.insert(entityList, specialHealth)
return entityList
end
 
function p._addAgilityObstacleSlotsAndPillars(entityList, skillName)
for i, level in ipairs(SkillData.Agility.obstacleUnlockLevels) do
local processed = {}
processed.entityName = 'Obstacle ' .. i
processed.entityType = 'obstacleslot'
processed.subType = 'obstacleslot'
processed.skillLevel = level
processed.otherReqs = {}
table.insert(entityList, processed)
end
-- Manually add pillars
table.insert(entityList, {['entityName'] = 'Passive Pillars', ['entityType'] = 'pillar', ['subType'] = 'pillar', ['skillLevel'] = 99, ['otherReqs'] = {}})
table.insert(entityList, {['entityName'] = 'Elite Passive Pillars', ['entityType'] = 'pillar', ['subType'] = 'pillar', ['skillLevel'] = 120, ['otherReqs'] = {}})
return entityList
end
 
function p._addGatherables(entityList, skillName)
-- Figure out what to look up based on the skill
local sourceData = {}
local subType = ''
if skillName == 'Woodcutting' then
sourceData = SkillData.Woodcutting.trees
subType = 'tree'
elseif skillName == 'Fishing' then
sourceData = SkillData.Fishing.fish
subType = 'fish'
elseif skillName == 'Mining' then
sourceData = SkillData.Mining.rockData
elseif skillName == 'Farming' then
sourceData = SkillData.Farming.recipes
end
for i, node in ipairs(sourceData) do
local gatherable = Items.getItemByID(node.productId)
local processed = {
['entityName'] = node.name,
['entityType'] = 'gathering',
['subType'] = subType,
['skillLevel'] = node.level,
['item'] = gatherable
}
-- Skill-specific overrides
if skillName == 'Fishing' then
processed['entityName'] = gatherable.name
elseif skillName == 'Mining' then
processed['subType'] = node.type
elseif skillName == 'Farming' then
processed['entityName'] = gatherable.name
processed['subType'] = node.categoryID
processed['seed'] = Items.getItemByID(node.seedCost.id)
end
processed['otherReqs'] = p._getGatherableReqs(node, skillName)
table.insert(entityList, processed)
end
return entityList
end
 
function p._addRecipes(entityList, skillName)
-- Figure out what to look up based on the skill
local sourceData = SkillData[skillName].recipes
local sameRecipeAndProduct = false
if skillName == 'Herblore' then
sameRecipeAndProduct = true
end
for i, recipe in ipairs(sourceData) do
local product = recipe
if not sameRecipeAndProduct then
product = Items.getItemByID(recipe.productID)
end
local processed = {
['entityName'] = product.name,
['entityType'] = 'artisan',
['subType'] = recipe.categoryID,
['skillLevel'] = recipe.level,
['item'] = product
}
table.insert(entityList, processed)
end
return entityList
end
 
function p._addSkillMastery(entityList, skillName)
-- Add the "Skill Mastery" perk when relevant
table.insert(entityList, {['entityName'] = 'Skill Mastery', ['entityType'] = 'special', ['subType'] = 'skillmastery', ['skillLevel'] = 99, ['otherReqs'] = {}})
return entityList
end
 
local SOURCE_FUNCS = {
['areas'] = p._addAreasWithSkillRequirement,
['spells'] = p._addSpells,
['altmagic'] = p._addAltMagic,
['prayers'] = p._addPrayers,
['gatheringitems'] = p._addGatherables,
['artisanitems'] = p._addRecipes,
['firemaking'] = p._addFiremakingActions,
['thieving'] = p._addThievingTargets,
['constellations'] = p._addConstellations,
['shop'] = p._addShopPurchasesWithSkillRequirements,
['farmingplots'] = p._addFarmingPlots,
['townshipunlocks'] = p._addTownshipUnlocks,
['agilityslots'] = p._addAgilityObstacleSlotsAndPillars,
['mastery'] = p._addSkillMastery
}
 
function p._prepareOtherReqs(entity)
local extraReqs = {}
if entity.otherReqs ~= nil and entity.otherReqs ~= {} then
-- Don't list a bazillion skills for the max skillcapes
if entity.entityName == 'Maximum Skillcape' then
return ' (requires level 99 in all skills)'
elseif entity.entityName == 'Superior Max Skillcape' then
return ' (requires level 120 in all skills)'
else
for i, req in ipairs(entity.otherReqs) do
-- TODO: "Completion" requirement? Might not be needed
if req.type == 'SkillLevel' then
local skillInfo = Icons.Icon({Constants.getSkillName(req.skillID), type='skill', notext='true'}) .. ' ' .. req.level
table.insert(extraReqs, skillInfo)
elseif req.type == 'DungeonCompletion' then
local dungeonName = GameData.getEntityByID('dungeons', req.dungeonID).name
-- If you only need to clear it once (Impending Darkness),
-- don't bother listing the count
if req.count > 1 then
table.insert(extraReqs, Icons.Icon({dungeonName, type='dungeon', qty=req.count, notext=true}) .. ' clears')
else
table.insert(extraReqs, Icons.Icon({dungeonName, type='dungeon', notext=true}) .. ' cleared')
end
elseif req.type == 'MonsterKilled' then
local monsterName = GameData.getEntityByID('monsters', req.monsterID).name
local monsterInfo = Icons.Icon({monsterName, type='monster', qty=req.count}) .. ' kills'
table.insert(extraReqs, monsterInfo)
elseif req.type == 'item' then
local itemInfo = Icons.Icon({req.item.name, type='item'})
table.insert(extraReqs, itemInfo)
elseif req.type == 'shop' then
table.insert(extraReqs, Shop._getPurchaseIcon({req.purchase}))
elseif req.type == 'totalMastery' then
table.insert(extraReqs, Shared.formatnum(req.mastery) .. ' ' .. Icons.Icon({req.skill, type='skill', notext=true}) .. ' ' .. Icons.Icon({'Mastery'}))
elseif req.type == 'TownshipBuilding' then
local building = Township._getBuildingByID(req.buildingID)
table.insert(extraReqs, Icons.Icon({building.name, type='building', qty=req.count}))
end
end
end
end
if not next(extraReqs) then
return ''
else
return ' (requires ' .. table.concat(extraReqs, ', ') .. ')'
end
end
 
function p._prepareSingleEntity(entity, skillName)
-- Special children that need extra attention
if entity.overrideText then
return entity.overrideText
end
if entity.subType == 'skillmastery' then
return 'Gain ' .. Icons.Icon({skillName, type='skill', notext='true'}) .. ' [[Mastery#The_Mastery_Pool|Skill Mastery]]'
end
if skillName == 'Farming' and entity.seed then
return 'Plant ' .. Icons.Icon({entity.seed.name, type='item'}) .. ' to grow ' .. Icons.Icon({entity.entityName, type='item'})
end
if skillName == 'Township' and entity.upgradesFrom then
return 'Upgrade ' .. Icons.Icon({entity.upgradesFrom.name, type='building'}) .. ' to ' .. Icons.Icon({entity.entityName, type='building'})
end
-- What are you doing with the thing you unlock? ("verbs")
-- What are you doing with the thing you unlock? ("verbs")
local verb = ''
local verb = ''
if VERBS_PER_SUBTYPE[entity.subType] then
if VERBS_PER_SUBTYPE[entity.subType] then
verb = VERBS_PER_SUBTYPE[entity.subType] .. ' '
verb = VERBS_PER_SUBTYPE[entity.subType] .. ' '
elseif VERBS_PER_SUBTYPE[entity.entityType] then
verb = VERBS_PER_SUBTYPE[entity.entityType] .. ' '
end
end
-- Icon overrides
-- Icon overrides
local iconType = entity.entityType
local iconType = entity.entityType
local iconLink = entity.entityName
local iconText = entity.entityName
local iconImg = entity.entityName
local noLink = ''
if entity.entityType == 'slayerArea' then
if entity.entityType == 'slayerArea' then
iconType = 'combatArea'
iconType = 'combatArea'
end
end
if entity.entityType == 'spell' and (entity.subType == 'aurora' or entity.subType == 'curse') then
return verb .. Icons.Icon({entity.entityName, type=iconType})
iconType = entity.subType
end
if entity.entityType == 'gathering' then
if entity.subType == 'fish' then
iconType = 'item'
elseif entity.subType == 'Essence' or entity.subType == 'Ore' or entity.subType == 'Gem' then
iconType = 'rock'
else
iconType = entity.subType
end
iconLink = entity.item.name
end
if entity.entityType == 'artisan' or entity.entityType == 'trader' then
iconType = 'item'
end
if entity.entityType == 'shop' then
iconType = string.lower(entity.subType)
end
if entity.entityType == 'plot' then
iconType = 'skill'
iconLink = 'Farming'
iconImg = 'Farming'
noLink = 'true'
end
if entity.entityType == 'obstacle' then
iconType = 'agility'
end
if entity.entityType == 'obstacleslot' then
iconType = 'agility'
iconLink = 'Obstacles'
end
if entity.entityType == 'pillar' then
iconType = 'agility'
iconLink = 'Passive_Pillars'
end
-- Any other requirements or post-scripts?
local extraReqs = p._prepareOtherReqs(entity)
local extraPost = ''
if entity.entityType == 'obstacle' then
extraPost = ' in ' .. entity.subType
end
return verb .. Icons.Icon({iconLink, iconText, img=iconImg, type=iconType, nolink=noLink}) .. extraPost .. extraReqs
end
end


function p._prepareGearSet(gearSet)
function p._prepareGearSet(gearSet, entity)
local icons = ''
local icons = ''
for i, entity in ipairs(gearSet.entities) do
for i, itemName in ipairs(gearSet.entities) do
-- Skip trimmed armor, which always starts with an open parnthesis
-- Skip trimmed armor, which always starts with an open parnthesis
if string.sub(entity, 1, 1) ~= '(' then
if string.sub(itemName, 1, 1) ~= '(' then
icons = icons .. Icons.Icon({entity, type='item', notext=true})
icons = icons .. Icons.Icon({itemName, type='item', notext=true})
end
end
end
end
return gearSet.verb .. ' ' .. icons .. ' ' .. gearSet.name
-- Get extra requirements for whicheve piece we processed first, as they
-- should all be the same
local extraReqs = p._prepareOtherReqs(entity)
return gearSet.verb .. ' ' .. icons .. ' ' .. gearSet.name .. extraReqs
end
end


function p._getSkillUnlockTable(skillName)
function p._getSkillUnlockTable(skillName, args)
-- local skillReqLabel = skillName:lower() .. 'LevelRequired'
local itemsOnly = args.itemsOnly ~= nil and args.itemsOnly or false
-- TODO: Pass these min/max level params along to filter by them
local minLevel = args.minLevel ~= nil and args.minLevel or 0
local maxLevel = args.maxLevel ~= nil and args.maxLevel or 999
-- What do we need to check for this skill? (avoid checking everything for
-- What do we need to check for this skill? Avoid checking everything for
-- every skill to save time)
-- every skill to save time, except for a few broad things
local entityList = {}
local entityList = {}
if Shared.contains(CHECK_ITEMS, skillName) then
entityList = p._addItemsWithSkillRequirement(entityList, skillName)
entityList = p._addItemsWithSkillRequirement(entityList, skillName)
end
if not itemsOnly then
if Shared.contains(CHECK_AREAS, skillName) then
entityList = p._addShopPurchasesWithSkillRequirements(entityList, skillName)
entityList = p._addAreasWithSkillRequirement(entityList, skillName)
entityList = p._addTraderItemsWithSkillRequirements(entityList, skillName)
entityList = p._addAgilityObstaclesWithSkillRequirements(entityList, skillName)
-- Now loop through the stuff relevant to this skill
for i, dataSource in ipairs(SKILL_CHECK_MAP[skillName]) do
entityList = SOURCE_FUNCS[dataSource](entityList, skillName)
end
end
end
Line 612: Line 1,477:
-- Sort the big list of everything
-- Sort the big list of everything
table.sort(entityList, function(a, b)  
table.sort(entityList, function(a, b)
local aSubTypeSort = a.subType
if SUBTYPE_SORT_OVERRIDES[a.subType] then
aSubTypeSort = SUBTYPE_SORT_OVERRIDES[a.subType]
end
local bSubTypeSort = b.subType
if SUBTYPE_SORT_OVERRIDES[b.subType] then
bSubTypeSort = SUBTYPE_SORT_OVERRIDES[b.subType]
end
-- Sort by level first
-- Sort by level first
if a.skillLevel ~= b.skillLevel then
if a.skillLevel ~= b.skillLevel then
Line 620: Line 1,493:
return TYPE_SORT_ORDER[a.entityType] < TYPE_SORT_ORDER[b.entityType]
return TYPE_SORT_ORDER[a.entityType] < TYPE_SORT_ORDER[b.entityType]
    -- Then by subtype
    -- Then by subtype
elseif a.subType ~= b.subType then
elseif aSubTypeSort ~= bSubTypeSort then
     return a.subType < b.subType
     return aSubTypeSort < bSubTypeSort
-- And finally by name
-- And finally by name
else
else
Line 640: Line 1,513:
-- Skip this one if it's in a gear set we've already listed
-- Skip this one if it's in a gear set we've already listed
local entityGearSet = nil
local entityGearSet = nil
for i, gearSet in ipairs(GEAR_SETS) do
if entity.entityType == 'item' or entity.entityType == 'shop' then
if Shared.contains(gearSet.entities, entity.entityName) then
for i, gearSet in ipairs(GEAR_SETS) do
entityGearSet = gearSet
if Shared.contains(gearSet.entities, entity.entityName) then
break
entityGearSet = gearSet
break
end
end
end
end
end
Line 664: Line 1,539:
local toInsert = ''
local toInsert = ''
if entityGearSet ~= nil then
if entityGearSet ~= nil then
toInsert = p._prepareGearSet(entityGearSet)
toInsert = p._prepareGearSet(entityGearSet, entity)
table.insert(processedSets, entityGearSet.name)
table.insert(processedSets, entityGearSet.name)
else  
else  
toInsert = p._prepareSingleEntity(entity)
toInsert = p._prepareSingleEntity(entity, skillName)
end
end
Line 681: Line 1,556:


function p.getSkillUnlockTable(frame)
function p.getSkillUnlockTable(frame)
local skillName = frame.args ~= nil and frame.args[1]
local args = frame.args ~= nil and frame.args or frame
return p._getSkillUnlockTable(skillName)
local skillName = args[1]
end
return p._getSkillUnlockTable(skillName, args)
 
function p.test()
local ret = {}
for i, gearSet in ipairs(GEAR_SETS) do
mw.logObject(gearSet)
break
--[[
if Shared.contains(gearSet.entities, 'Bronze Boots') then
ret = gearSet
break
end
--]]
end
return ret
end
end


return p
return p
73

edits