Module:LevelUpTable/Data: Difference between revisions

From Melvor Idle
(Add additional requirements for Astrology)
(Remove deprecated code)
 
(9 intermediate revisions by the same user not shown)
Line 9: Line 9:
local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local FL = require('Module:FunList')


local UnlockData = {}
local UnlockData = {}
UnlockData.__index = UnlockData
UnlockData.__index = UnlockData


function UnlockData.new(id, name, level, skill)
function UnlockData.new(id, name, level, skill, category)
     local self = setmetatable({}, UnlockData)
     local self = setmetatable({}, UnlockData)
     self.name = name
     self.name = name
     self.level = level
     self.level = level
     self.skill = skill
     self.skill = skill
    self.category = category or skill
     self.id = id
     self.id = id
     self.otherRequirements = nil
     self.otherRequirements = nil
     return self
     return self
end
--==== Helper functions ====--
-- Mimicks the C# Select method.
function Select(list, selector)
    local result = {}
    for _, item in ipairs(list) do
        table.insert(result, selector(item))
    end
    return result
end
-- Mimicks the C# Where method.
function Where(tbl, predicate)
    local result = {}
    for _, v in ipairs(tbl) do
        if predicate(v) then
            table.insert(result, v)
        end
    end
    return result
end
function Concat(...)
    local args = {...}
    local result = {}
    for _, tbl in ipairs(args) do
        for _, value in ipairs(tbl) do
            table.insert(result, value)
        end
    end
    return result
end
end


Line 62: Line 32:
return 'melvorD:Melvor'
return 'melvorD:Melvor'
end
end
end
function getDataSet(skillData, realm)
return GameData.getEntities(skillData, function(x) return Skills.getRecipeRealm(x) == realm.id end)
end
function getDataSetId(skillData, realm)
return GameData.getEntities(skillData, function(x) return getRealmFromID(x) == realm.id end)
end
end


Line 75: Line 37:
function getWoodcuttingData(realm)
function getWoodcuttingData(realm)
local skillID = 'Woodcutting'
local skillID = 'Woodcutting'
local data = getDataSet(SkillData.Woodcutting.trees, realm)
 
return FL.new(SkillData.Woodcutting.trees)
return Select(data, function(x)  
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID)
:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
end)
:toTable()
end
end


function getMiningData(realm)
function getMiningData(realm)
local skillID = 'Mining'
local skillID = 'Mining'
local data = getDataSet(SkillData.Mining.rockData, realm)
 
return FL.new(SkillData.Woodcutting.rockData)
return Select(data, function(x)  
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID)
:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
end)
:toTable()
end
end


function getFishingData(realm)
function getFishingData(realm)
local skillID = 'Fishing'
local skillID = 'Fishing'
local data = getDataSet(SkillData.Fishing.fish, realm)
 
return FL.new(SkillData.Woodcutting.fish)
return Select(data, function(x)  
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID)
:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
end)
:toTable()
end
end


function getThievingData(realm)
function getThievingData(realm)
local skillID = 'Thieving'
local skillID = 'Thieving'
local data = getDataSet(SkillData.Thieving.npcs, realm)
 
return FL.new(SkillData.Woodcutting.npcs)
return Select(data, function(x)  
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID)
:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
end)
:toTable()
end
end


function getFarmingData(realm)
function getFarmingData(realm)
local skillID = 'Farming'
local skillID = 'Farming'
local data = getDataSet(SkillData.Farming.recipes, realm)
-- Create lookup for plot category name.
-- Create lookup for plot category name.
local plotLookup = {}
local plotLookup = FL.new(SkillData.Farming.categories)
for _, plot in ipairs(SkillData.Farming.categories) do
:toDictionary(function(k) return k.id end,
        plotLookup[plot.id] = plot.name
  function(v) return v.name end)
    end
 
local seeds = FL.new(SkillData.Farming.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local productItem = Items.getItemByID(x.productId)
return UnlockData.new(productItem.id, productItem.name, Skills.getRecipeLevel(skillID, x), skillID)
end)


local seeds = Select(data, function(x)  
local plots = FL.new(SkillData.Farming.plots)
local productItem = Items.getItemByID(x.productId)
:where(function(x) return getRealmFromID(x) == realm.id end)
return UnlockData.new(productItem.id, productItem.name, Skills.getRecipeLevel(skillID, x), skillID)
:select(function(x)  
end)
return UnlockData.new(x.id, plotLookup[x.categoryID], Skills.getRecipeLevel(skillID, x), skillID, "Farming Plot")
end)
local plotData = getDataSetId(SkillData.Farming.plots, realm)
local plots = Select(plotData, function(x)
return UnlockData.new(x.id, plotLookup[x.categoryID], Skills.getRecipeLevel(skillID, x), "Farming Plot")
end)


return Concat(seeds, plots)
return seeds:concat(plots)
:toTable()
end
end


function getAstrologyData(realm)
function getAstrologyData(realm)
local skillID = 'Astrology'
local skillID = 'Astrology'
local data = getDataSet(SkillData.Astrology.recipes, realm)
 
return FL.new(SkillData.Woodcutting.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
:toTable()
end
 
function getAgilityData(realm)
local skillID = 'Agility'
local pillarLevels = {
melvorF = 99,
melvorTotH = 120,
melvorItA = 60
}
local pillars = FL.new(SkillData.Agility.pillars)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local ns, _ = Shared.getLocalID(x.id)
return UnlockData.new(x.id, x.name, pillarLevels[ns], skillID)
end)
 
return pillars:concat(getAgilityRequirements(skillID, realm))
  :toTable()
end
 
function getFiremakingData(realm)
local skillID = 'Firemaking'
 
return FL.new(SkillData.Firemaking.logs)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local logs = Items.getItemByID(x.logID)
return UnlockData.new(x.id, logs.name, Skills.getRecipeLevel(skillID, x), skillID)
end):toTable()
end
 
function getCookingData(realm)
local skillID = 'Cooking'
 
return FL.new(SkillData.Cooking.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local foodItem = Items.getItemByID(x.productID)
return UnlockData.new(foodItem.id, foodItem.name, Skills.getRecipeLevel(skillID, x), skillID, x.categoryID)
end):toTable()
end
 
function getSmithingData(realm)
local skillID = 'Smithing'
return Select(data, function(x)  
return FL.new(SkillData.Smithing.recipes)
return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
end)
:select(function(x)
local product = Items.getItemByID(x.productID)
return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID, x.categoryID)
end):toTable()
end
 
function getFletchingData(realm)
local skillID = 'Fletching'
return FL.new(SkillData.Fletching.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local product = Items.getItemByID(x.productID)
return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)
end):toTable()
end
 
function getCraftingData(realm)
local skillID = 'Crafting'
return FL.new(SkillData.Crafting.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local product = Items.getItemByID(x.productID)
return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)
end):toTable()
end
 
function getRunecraftingData(realm)
local skillID = 'Runecrafting'
return FL.new(SkillData.Runecrafting.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local product = Items.getItemByID(x.productID)
return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)
end):toTable()
end
 
function getHerbloreData(realm)
local skillID = 'Herblore'
 
return FL.new(SkillData.Herblore.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local lastPotID = FL.new(x.potionIDs):last()
local lastPot = Items.getItemByID(lastPotID)
return UnlockData.new(lastPot.id, lastPot.name, Skills.getRecipeLevel(skillID, x), skillID)
end):toTable()
end
 
function getSummoningData(realm)
local skillID = 'Summoning'
return FL.new(SkillData.Summoning.recipes)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
:select(function(x)
local product = Items.getItemByID(x.productID)
return UnlockData.new(x.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)
end):toTable()
end
end


Line 148: Line 220:
function getUnlockReqs(constellation)
function getUnlockReqs(constellation)
if constellation.abyssalModifiers == nil then return nil end
if constellation.abyssalModifiers == nil then return nil end
for _, mod in ipairs(constellation.abyssalModifiers) do
local mod = FL.new(constellation.abyssalModifiers):firstOrDefault(function(mod)
        if mod.unlockRequirements then
return mod.unlockRequirements ~= nil and
            for _, req in ipairs(mod.unlockRequirements) do
  FL.new(mod.unlockRequirements):any(function(req) return req.skillID == skillID end)
                if req.skillID == skillID then
end, nil)
                -- Return the unlockRequirements table, so we can reuse this function later to retrieve unlock data.
                return mod.unlockRequirements
return mod and mod.unlockRequirements or nil
                end
                end
            end
end
    return nil
end
end
 
-- Gets the unlockRequirement for the tagged skill.
return FL.new(SkillData.Astrology.recipes)
function getSkillUnlock(unlockRequirements)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id and getUnlockReqs(x) end)
for _, req in ipairs(unlockRequirements) do
:select(function(const)
if req.skillID == skillID then
local unlockReqs = FL.new(getUnlockReqs(const))
return req
local myUnlocks = unlockReqs:first(function(req) return req.skillID == skillID end)
local otherUnlocks = unlockReqs:where(function(req) return req.skillID ~= skillID end)
local data = UnlockData.new(const.id, const.name, myUnlocks.level, skill, "Astrology")
data.otherRequirements = {}
table.insert(data.otherRequirements, UnlockData.new(const.id, const.name, Skills.getRecipeLevel(AstroID, const), AstroID))
for _, req in pairs(otherUnlocks) do
table.insert(data.otherRequirements, UnlockData.new(const.id, const.name, req.level, req.type))
end
end
end
return data
end):toTable()
end
 
function getAgilityRequirements(skill, realm)
local skillID = Constants.getSkillID(skill)
local AgilitySkillID = Constants.getSkillID('Agility')
local AgilityID = 'Agility'
 
-- Filter obstacles by realm.
local obstacles = FL.new(SkillData.Agility.obstacles)
:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
-- If the skill is something other than the Agility skill, filter obstacles that contain
-- the provided skill as a requirement.
if skill ~= AgilityID then
obstacles:where(function(obstacle)
return obstacle.skillRequirements ~= nil and
FL.new(obstacle.skillRequirements):any(function(req) return req.skillID == skillID end)
end)
end
end
 
-- Gets all unlockRequirements that are not for the tagged skill.
-- Add agility skill requirement to requirements list.
function getOtherUnlock(unlockRequirements)
return obstacles:select(function(o)
return Where(unlockRequirements,
local reqs = FL.new(o.skillRequirements)
function(req)  
:select(function(req) return { level = req.level, skillID = req.skillID } end)
return req.skillID ~= skillID  
:append({ level = Skills.getRecipeLevelRealm('Agility', o), skillID = AgilitySkillID})
end)
 
end
local myUnlock = reqs:first(function(req) return req.skillID == skillID end)
local otherUnlocks = reqs:where(function(req) return req.skillID ~= skillID end)
local filterFunc = function(x)
return Skills.getRecipeRealm(x) == realm.id and getUnlockReqs(x)
end
local constellations = GameData.getEntities(SkillData.Astrology.recipes, filterFunc)
return Select(constellations, function(const)
local unlockReqs = getUnlockReqs(const)
local myUnlocks = getSkillUnlock(unlockReqs)
local otherUnlocks = getOtherUnlock(unlockReqs)
local data = UnlockData.new(const.id, const.name, myUnlocks.level, skill)
local data = UnlockData.new(o.id, o.name, myUnlock.level, skill, 'AgilityObstacle')
data.otherRequirements = {}
data.otherRequirements = otherUnlocks:select(function(req)
table.insert(data.otherRequirements, UnlockData.new(const.id, const.name, Skills.getRecipeLevel(AstroID, const), AstroID))
local _, skillName = GameData.getLocalID(req.skillID)
for _, req in ipairs(otherUnlocks) do
return UnlockData.new(o.id, o.name, req.level, skillName)
table.insert(data.otherRequirements, UnlockData.new(const.id, const.name, req.level, req.type))
end):toTable()
end
 
return data
return data
end)
end):toTable()
end
end



Latest revision as of 16:45, 20 July 2024

Documentation for this module may be created at Module:LevelUpTable/Data/doc

-- SkillData object that acts as an interface for data shared between skills.
local p = {}

local Debug = require('Module:Debug') --  < Remove when module is finished.
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Skills = require('Module:Skills')
local Items = require('Module:Items')
local Shared = require('Module:Shared')
local Constants = require('Module:Constants')
local FL = require('Module:FunList')

local UnlockData = {}
UnlockData.__index = UnlockData

function UnlockData.new(id, name, level, skill, category)
    local self = setmetatable({}, UnlockData)
    self.name = name
    self.level = level
    self.skill = skill
    self.category = category or skill
    self.id = id
    self.otherRequirements = nil
    return self
end

function getRealmFromID(obj)
	local ns, _ = Shared.getLocalID(obj.id)
	if ns == 'melvorItA' then
		return 'melvorItA:Abyssal'
	else
		return 'melvorD:Melvor'
	end
end

--==== Skill Data Collection ====--
function getWoodcuttingData(realm)
	local skillID = 'Woodcutting'

	return FL.new(SkillData.Woodcutting.trees)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
		:toTable()
end

function getMiningData(realm)
	local skillID = 'Mining'

	return FL.new(SkillData.Woodcutting.rockData)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
		:toTable()
end

function getFishingData(realm)
	local skillID = 'Fishing'

	return FL.new(SkillData.Woodcutting.fish)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
		:toTable()
end

function getThievingData(realm)
	local skillID = 'Thieving'

	return FL.new(SkillData.Woodcutting.npcs)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
		:toTable()
end

function getFarmingData(realm)
	local skillID = 'Farming'
	-- Create lookup for plot category name.
	local plotLookup = FL.new(SkillData.Farming.categories)
		:toDictionary(function(k) return k.id end,
					  function(v) return v.name end)

	local seeds = FL.new(SkillData.Farming.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local productItem = Items.getItemByID(x.productId)
			return UnlockData.new(productItem.id, productItem.name, Skills.getRecipeLevel(skillID, x), skillID)		
		end)

	local plots = FL.new(SkillData.Farming.plots)
		:where(function(x) return getRealmFromID(x) == realm.id end)
		:select(function(x) 
			return UnlockData.new(x.id, plotLookup[x.categoryID], Skills.getRecipeLevel(skillID, x), skillID, "Farming Plot")
		end)

	return seeds:concat(plots)
				:toTable()
end

function getAstrologyData(realm)
	local skillID = 'Astrology'

	return FL.new(SkillData.Woodcutting.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x) return UnlockData.new(x.id, x.name, Skills.getRecipeLevel(skillID, x), skillID) end)
		:toTable()
end

function getAgilityData(realm)
	local skillID = 'Agility'
	local pillarLevels = {
		melvorF = 99,
		melvorTotH = 120,
		melvorItA = 60
	}
	
	local pillars = FL.new(SkillData.Agility.pillars)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local ns, _ = Shared.getLocalID(x.id)
			return UnlockData.new(x.id, x.name, pillarLevels[ns], skillID)	
		end)

	return pillars:concat(getAgilityRequirements(skillID, realm))
				  :toTable()
end

function getFiremakingData(realm)
	local skillID = 'Firemaking'

	return FL.new(SkillData.Firemaking.logs)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x) 
			local logs = Items.getItemByID(x.logID)
			return UnlockData.new(x.id, logs.name, Skills.getRecipeLevel(skillID, x), skillID)
		end):toTable()
end

function getCookingData(realm)
	local skillID = 'Cooking'

	return FL.new(SkillData.Cooking.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local foodItem = Items.getItemByID(x.productID)
			return UnlockData.new(foodItem.id, foodItem.name, Skills.getRecipeLevel(skillID, x), skillID, x.categoryID)			
		end):toTable()
end

function getSmithingData(realm)
	local skillID = 'Smithing'
	
	return FL.new(SkillData.Smithing.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local product = Items.getItemByID(x.productID)
			return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID, x.categoryID)			
		end):toTable()
end

function getFletchingData(realm)
	local skillID = 'Fletching'
	
	return FL.new(SkillData.Fletching.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)	
		:select(function(x)
			local product = Items.getItemByID(x.productID)
			return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)
		end):toTable()
end

function getCraftingData(realm)
	local skillID = 'Crafting'
	
	return FL.new(SkillData.Crafting.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local product = Items.getItemByID(x.productID)
			return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)
		end):toTable()
end

function getRunecraftingData(realm)
	local skillID = 'Runecrafting'
	
	return FL.new(SkillData.Runecrafting.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local product = Items.getItemByID(x.productID)
			return UnlockData.new(product.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)		
		end):toTable()
end

function getHerbloreData(realm)
	local skillID = 'Herblore'

	return FL.new(SkillData.Herblore.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local lastPotID = FL.new(x.potionIDs):last()
			local lastPot = Items.getItemByID(lastPotID)
			return UnlockData.new(lastPot.id, lastPot.name, Skills.getRecipeLevel(skillID, x), skillID)
		end):toTable()
end

function getSummoningData(realm)
	local skillID = 'Summoning'
	
	return FL.new(SkillData.Summoning.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		:select(function(x)
			local product = Items.getItemByID(x.productID)
			return UnlockData.new(x.id, product.name, Skills.getRecipeLevel(skillID, x), skillID)			
		end):toTable()
end

--==== Other Requirements Collection ====--
function getAstrologyRequirements(skill, realm)
	-- Only Abyssal Astrology has level unlock requirements as of V1.3
	local skillID = Constants.getSkillID(skill)
	local AstroID = 'Astrology'
	-- Find if this constellation has the provided skill as an unlock requirement.
	function getUnlockReqs(constellation)
		if constellation.abyssalModifiers == nil then return nil end
		local mod = FL.new(constellation.abyssalModifiers):firstOrDefault(function(mod)
				return mod.unlockRequirements ~= nil and 
					   FL.new(mod.unlockRequirements):any(function(req) return req.skillID == skillID end)
		end, nil)
		
		return mod and mod.unlockRequirements or nil
	end

	return FL.new(SkillData.Astrology.recipes)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id and getUnlockReqs(x)	end)
		:select(function(const) 
			local unlockReqs = FL.new(getUnlockReqs(const))
			local myUnlocks = unlockReqs:first(function(req) return req.skillID == skillID end)
			local otherUnlocks = unlockReqs:where(function(req) return req.skillID ~= skillID end)
		
			local data = UnlockData.new(const.id, const.name, myUnlocks.level, skill, "Astrology")
			data.otherRequirements = {}
			table.insert(data.otherRequirements, UnlockData.new(const.id, const.name, Skills.getRecipeLevel(AstroID, const), AstroID))
			for _, req in pairs(otherUnlocks) do
				table.insert(data.otherRequirements, UnlockData.new(const.id, const.name, req.level, req.type))
			end
			return data			
		end):toTable()
end

function getAgilityRequirements(skill, realm)
	local skillID = Constants.getSkillID(skill)
	local AgilitySkillID = Constants.getSkillID('Agility')
	local AgilityID = 'Agility'

	-- Filter obstacles by realm.
	local obstacles = FL.new(SkillData.Agility.obstacles)
		:where(function(x) return Skills.getRecipeRealm(x) == realm.id end)
		
	-- If the skill is something other than the Agility skill, filter obstacles that contain
	-- the provided skill as a requirement.
	if skill ~= AgilityID then
		obstacles:where(function(obstacle)
			return obstacle.skillRequirements ~= nil and
			FL.new(obstacle.skillRequirements):any(function(req) return req.skillID == skillID end)
		end)
	end

	-- Add agility skill requirement to requirements list.
	return obstacles:select(function(o)
		local reqs = FL.new(o.skillRequirements)
			:select(function(req) return { level = req.level, skillID = req.skillID } end)
			:append({ level = Skills.getRecipeLevelRealm('Agility', o), skillID = AgilitySkillID})

		local myUnlock = reqs:first(function(req) return req.skillID == skillID end)
		local otherUnlocks = reqs:where(function(req) return req.skillID ~= skillID end)
		
		local data = UnlockData.new(o.id, o.name, myUnlock.level, skill, 'AgilityObstacle')
		data.otherRequirements = otherUnlocks:select(function(req)
			local _, skillName = GameData.getLocalID(req.skillID)
			return UnlockData.new(o.id, o.name, req.level, skillName)
		end):toTable()

		return data
	end):toTable()
end

function p.test()
	local realmName = 'Abyssal Realm'
	local realm = Skills.getRealmFromName(realmName)
	Debug.log(getAstrologyRequirements('Herblore', realm))
end

p.UnlockData = UnlockData
return p