Module:Skills/Agility

From Melvor Idle

Documentation for this module may be created at Module:Skills/Agility/doc

local p = {}

local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Items = require('Module:Items')
local Icons = require('Module:Icons')

function p.getObstacleByID(obstID)
	return GameData.getEntityByID(SkillData.Agility.obstacles, obstID)
end

function p.getObstacle(name)
	return GameData.getEntityByName(SkillData.Agility.obstacles, name)
end

function p.getObstacles(checkFunc)
	return GameData.getEntities(SkillData.Agility.obstacles, checkFunc)
end

function p.getPillars(checkFunc)
	local result = nil
	local keys = { 'pillars', 'elitePillars' }
	for i, key in ipairs(keys) do
		local pillars = GameData.getEntities(SkillData.Agility[key], checkFunc)
		if result == nil then
			result = pillars
		else
			for k, pillar in ipairs(pillars) do
				table.insert(result, pillar)
			end
		end
	end
	if result == nil then
		result = {}
	end
	return result
end

function p._getObstacleLevel(obstacle)
	if obstacle.category ~= nil then
		if obstacle.category == 0 then
			return 1
		else
			return SkillData.Agility.obstacleUnlockLevels[obstacle.category]
		end
	else
		local _, localID = GameData.getLocalID(obstacle.id)
		if localID ~= nil then
			if string.find(localID, '^Pillar') ~= nil then
				return 99
			elseif string.find(localID, '^ElitePillar') ~= nil then
				return 120
			end
		end
	end
end

function p._getObstacleRequirements(obstacle)
	local resultPart = {}
	local level = p._getObstacleLevel(obstacle)
	if level ~= nil then
		table.insert(resultPart, Icons._SkillReq('Agility', level))
	end
	if type(obstacle.skillRequirements) == 'table' then
		for i, skillReq in ipairs(obstacle.skillRequirements) do
			local skillName = Constants.getSkillName(skillReq.skillID)
			if skillName ~= nil then
				table.insert(resultPart, Icons._SkillReq(skillName, skillReq.level))
			end
		end
	end
	return table.concat(resultPart, '<br/>')
end

function p._getObstacleCosts(obstacle)
	local costs = {}
	if obstacle.gpCost > 0 then table.insert(costs, Icons.GP(obstacle.gpCost)) end
	if obstacle.scCost > 0 then table.insert(costs, Icons.SC(obstacle.scCost)) end
	for j, itemCost in ipairs(obstacle.itemCosts) do
		local item = Items.getItemByID(itemCost.id)
		table.insert(costs, Icons.Icon({item.name, type='item', qty = itemCost.quantity, notext=true}))
	end
	return table.concat(costs, '<br/>')
end

function p.getObstacleCourseTable(frame)
	local result = ''

	result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Slot!!Name!!XP!!GP!!Time!!XP/s!!GP/s'--!!XP/s!!GP/s (left comment here for posterity)
	result = result..'!!Bonuses!!Requirements!!Cost'

	local catLog = {}
	local obstacles = p.getObstacles(function(obst) return true end)
	table.sort(obstacles, function(a, b) return a.category < b.category end)

	local catCounts = {}
	for i, obst in ipairs(obstacles) do
		if catCounts[obst.category] == nil then
			catCounts[obst.category] = 1
		else
			catCounts[obst.category] = catCounts[obst.category] + 1
		end
	end

	for i, obst in ipairs(obstacles) do
		result = result..'\r\n|-'
		result = result..'\r\n|'
		if catLog[obst.category] == nil then
			local rowspan = catCounts[obst.category]
			result = result..'rowspan="'..rowspan..'" style="border:1px solid black"|'..(obst.category + 1)..'||'
			catLog[obst.category] = true
		end
		result = result .. Icons.getExpansionIcon(obst.id) .. obst.name

		--After the name & category, doing XP, GP, Time, and rates
		local XP = obst.baseExperience
		local GP = obst.gpReward
		local Time = obst.baseInterval / 1000
		result = result..'||'..XP..'||data-sort-value="'..GP..'"|'..Icons.GP(GP)
		result = result..'||data-sort-value="'..Time..'"|'..Shared.timeString(Time, true)
		-- Readded XP/Time and GP/Time (previously commented out)
		result = result..'||'..Shared.round(XP / Time, 2, 2)
		result = result..'||data-sort-value="'..GP/Time..'"|'..Icons.GP(Shared.round(GP/Time, 2, 2))

		local bonuses = {}
		--After that, adding the bonuses
		for bonusName, bonusValue in pairs(obst.modifiers) do
			table.insert(bonuses, Constants._getModifierText(bonusName, bonusValue))
		end
		if Shared.tableIsEmpty(bonuses) then
			table.insert(bonuses, '<span style="color:red">None :(</span>')
		end
		result = result..'||'..table.concat(bonuses, '<br/>')

		--Grabbing requirements to create
		result = result..'|| ' .. p._getObstacleRequirements(obst)

		--Finally, the cost
		result = result..'|| data-sort-value="'..obst.gpCost..'"|'..p._getObstacleCosts(obst)
	end

	result = result..'\r\n|}'

	return result
end

function p.getPassivePillarTable(frame)
	local result = ''

	result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Name!!Bonuses!!Cost'

	local pillars = p.getPillars(function(pillar) return true end)
	for i, pill in ipairs(pillars) do
		result = result..'\r\n|-'
		result = result..'\r\n|' .. Icons.getExpansionIcon(pill.id) .. pill.name

		--After that, adding the bonuses
		local bonuses = {}
		for bonusName, bonusValue in pairs(pill.modifiers) do
			table.insert(bonuses, Constants._getModifierText(bonusName, bonusValue))
		end
		if Shared.tableIsEmpty(bonuses) then
			table.insert(bonuses, '<span style="color:red">None :(</span>')
		end
		result = result..'||'..table.concat(bonuses, '<br/>')

		--Finally, the cost
		result = result..'|| data-sort-value="'..pill.gpCost..'"|'..p._getObstacleCosts(pill)
	end

	result = result..'\r\n|}'

	return result
end

function p.getObstaclesForItem(itemID)
	local costFunc =
		function(obst)
			for i, itemCost in ipairs(obst.itemCosts) do
				if itemCost.id == itemID then
					return true
				end
			end
			return false
		end
	local pillars = p.getPillars(costFunc)

	local result = p.getObstacles(costFunc)
	if result == nil or Shared.tableIsEmpty(result) then
		result = pillars
	else
		for i, pillar in ipairs(pillars) do
			table.insert(result, pillar)
		end
	end

	return result
end

function p._getCourseTable(obstacleNames)
	local result = ''
	local obstacles = {}
	for i, name in ipairs(obstacleNames) do
		local obst = p.getObstacle(Shared.trim(name))
		if obst == nil then
			result = result .. Shared.printError('Invalid Obstacle Name "' .. name .. '"') .. '<br/>'
		else
			table.insert(obstacles, obst)
		end
	end

	result = result..'{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Slot!!Name!!Bonuses!!Requirements!!Cost'

	local catLog = {}
	
	table.sort(obstacles, function(a, b) return a.category < b.category end)

	local catCounts = {}
	for i, obst in ipairs(obstacles) do
		if catCounts[obst.category] == nil then
			catCounts[obst.category] = 1
		else
			catCounts[obst.category] = catCounts[obst.category] + 1
		end
	end

	for i, obst in ipairs(obstacles) do
		result = result..'\r\n|-'
		result = result..'\r\n|'
		if catLog[obst.category] == nil then
			local rowspan = catCounts[obst.category]
			result = result..'rowspan="'..rowspan..'" style="border:1px solid black"|'..(obst.category + 1)..'||'
			catLog[obst.category] = true
		end
		result = result..obst.name

		local bonuses = {}
		--After that, adding the bonuses
		for bonusName, bonusValue in pairs(obst.modifiers) do
			table.insert(bonuses, Constants._getModifierText(bonusName, bonusValue))
		end
		if Shared.tableIsEmpty(bonuses) then
			table.insert(bonuses, '<span style="color:red">None :(</span>')
		end
		result = result..'||'..table.concat(bonuses, '<br/>')

		--Grabbing requirements to create
		result = result..'|| ' .. p._getObstacleRequirements(obst)

		--Finally, the cost
		result = result..'|| data-sort-value="'..obst.gpCost..'"|'..p._getObstacleCosts(obst)
	end

	result = result..'\r\n|}'

	return result
end

function p.getCourseTable(frame)
	local obstNameStr = frame.args ~= nil and frame.args[1] or frame
	local obstacleNames = Shared.splitString(obstNameStr, ',')
	
	return p._getCourseTable(obstacleNames)
end

return p