Module:Skills/Agility

From Melvor Idle
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

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

local p = {}

local Constants = require('Module:Constants')
local Num = require('Module:Number')
local Shared = require('Module:Shared')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Skills = require('Module:Skills')
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.getPillar(name)
	local result = p.getPillars(
		function(x)
			return x.name == name
		end
	)
	
	return result[1]
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

-- Applies the cost reduction to the provided ItemCosts table.
-- CostReduction is a table { ['GP'] = num, ['SC'] = num, ['Item'] = {} }
-- Reduction values range from 0 to 100.
function p.applyCostReduction(itemCosts, costReduction)
	if costReduction == nil then return itemCosts end

	local gp =   Num.clamp((costReduction['GP'] or 0), 0, 100) / 100
	local sc =   Num.clamp((costReduction['SC'] or 0), 0, 100) / 100
	local item = Num.clamp((costReduction['Item'] or 0), 0, 100) / 100
	
	if gp > 0 and itemCosts['GP'] then
		itemCosts['GP'] = math.ceil(itemCosts['GP'] * (1 - gp))
	end
	if sc > 0 and itemCosts['SC'] then
		itemCosts['SC'] = math.ceil(itemCosts['SC'] * (1 - sc))
	end
	
	local items = itemCosts['Items']
	if item > 0 then
		for k, v in pairs(items) do
			items[k] = math.ceil(items[k] * (1 - item))
		end
	end
	
	itemCosts['Items'] = items
	return itemCosts
end

--- Gets all required levels to build the given obstacle.
function p.getObstacleRequirements(obstacle)
	local levelRequirements = {}
	
	-- Add agility level requirement.
	levelRequirements['Agility'] = Skills.getRecipeLevel('Agility', obstacle)

	-- Add other level requirements.
	if type(obstacle.skillRequirements) == 'table' then
		for i, skillReq in ipairs(obstacle.skillRequirements) do
			local skillName = Constants.getSkillName(skillReq.skillID)
			if skillName ~= nil then
				levelRequirements[skillName] = skillReq.level
			end
		end
	end
	
	return levelRequirements
end

-- Gets all items and gp/sc costs required to build the given obstacle.
function p.getObstacleCosts(obstacle)
	local costs = {}
	local items = {}

	if obstacle.gpCost > 0 then
		costs['GP'] = obstacle.gpCost
	end
	if obstacle.scCost > 0 then
		costs['SC'] = obstacle.scCost
	end

	for j, itemCost in ipairs(obstacle.itemCosts) do
		local item = Items.getItemByID(itemCost.id)
		items[item.name] = itemCost.quantity
	end
	
	costs['Items'] = items
	return costs
end

function p._getObstacleRequirements(obstacle)
	local resultPart = {}
	local requirements = p.getObstacleRequirements(obstacle)
	
	for skill, level in pairs(requirements) do
		table.insert(resultPart, Icons._SkillReq(skill, level))
	end

	return table.concat(resultPart, '<br/>')
end

function p._getObstacleCosts(obstacle)
	local costs = {}
	local obstacleCosts = p.getObstacleCosts(obstacle)

	-- Make sure SC and GP appear at the top.
	if obstacleCosts['GP'] then table.insert(costs, Icons.GP(obstacleCosts['GP'])) end
	if obstacleCosts['SC'] then table.insert(costs, Icons.SC(obstacleCosts['SC'])) end
	for item, amount in pairs(obstacleCosts['Items']) do
		table.insert(costs, Icons.Icon({item, type='item', qty = amount, 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!!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 .. 'id="'..string.gsub(obst.name,' ', '')..'"|'.. 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|' .. 'id="'..string.gsub(pill.name,' ', '')..'"|'..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

return p