Module:Skills/Agility: Difference between revisions

From Melvor Idle
(Remove unused modules/data; use ipairs instead of skpairs where possible to respect data order; getObstacleCourseTable: Display obstacles in same order as in-game)
(Account for AP and ASC; Fix GP icon and GP text in abyssal agility table)
 
(27 intermediate revisions by 5 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local SkillData = mw.loadData('Module:Skills/data')


local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local Num = require('Module:Number')
local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local Common = require('Module:Common')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Modifiers = require('Module:Modifiers')
local Skills = require('Module:Skills')
local Items = require('Module:Items')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Num = require('Module:Number')


function p.getObstacleByID(obstID)
function p.getObstacleByID(obstID)
  local result = Shared.clone(SkillData.Agility.Obstacles[obstID + 1])
return GameData.getEntityByID(SkillData.Agility.obstacles, obstID)
  return result
end
end


function p.getObstacle(name)
function p.getObstacle(name)
  for i, obst in ipairs(SkillData.Agility.Obstacles) do
return GameData.getEntityByName(SkillData.Agility.obstacles, name)
    if obst.name == name then
end
      local result = Shared.clone(obst)
 
      result.id = i - 1
function p.getPillar(name)
      return result
local result = p.getPillars(
    end
function(x)
  end
return x.name == name
  return nil
end
)
return result[1]
end
end


function p.getObstacles(checkFunc)
function p.getObstacles(checkFunc)
  local result = {}
return GameData.getEntities(SkillData.Agility.obstacles, checkFunc)
  for i, obst in ipairs(SkillData.Agility.Obstacles) do
    if checkFunc(obst) then
      local newObst = Shared.clone(obst)
      newObst.id = i - 1
      table.insert(result, newObst)
    end
  end
  return result
end
end


function p.getPillars(checkFunc)
function p.getPillars(checkFunc)
   local result = {}
return GameData.getEntities(SkillData.Agility.pillars, checkFunc)
  for i, pillar in ipairs(SkillData.Agility.Pillars) do
end
    if checkFunc(pillar) then
 
      local newPillar = Shared.clone(pillar)
-- Applies the cost reduction to the provided ItemCosts table.
      newPillar.id = i - 1
-- CostReduction is a table { ['GP'] = num, ['SC'] = num, ['Item'] = {} }
      table.insert(result, newPillar)
-- Reduction values range from 0 to 100.
    end
function p.applyCostReduction(itemCosts, costReduction)
  end
if costReduction == nil then return itemCosts end
  return result
 
local gp =  Num.clamp((costReduction['GP'] or 0), 0, 100) / 100
local sc =  Num.clamp((costReduction['SC'] or 0), 0, 100) / 100
local ap =  Num.clamp((costReduction['AP'] or 0), 0, 100) / 100
local asc =   Num.clamp((costReduction['ASC'] 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
if ap > 0 and itemCosts['AP'] then
itemCosts['AP'] = math.ceil(itemCosts['AP'] * (1 - ap))
end
if asc > 0 and itemCosts['ASC'] then
itemCosts['ASC'] = math.ceil(itemCosts['ASC'] * (1 - asc))
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 realmRequirements = p.getObstacleRequirementsRealm(obstacle)
local levelRequirements = {}
for skillName, skillReq in pairs(realmRequirements) do
levelRequirements[skillName] = skillReq.level
end
return levelRequirements
end
 
--- Gets all required levels to build the given obstacle.
function p.getObstacleRequirementsRealm(obstacle)
local levelRequirements = {}
-- Add agility level requirement.
local agilityLevelRequirement, isAbyssal = Skills.getRecipeLevelRealm('Agility', obstacle)
levelRequirements['Agility'] = {
level = agilityLevelRequirement,
isAbyssal = isAbyssal
}
 
-- 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] = {
level = skillReq.level,
isAbyssal = skillReq.type == 'AbyssalLevel'
}
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 = {}
 
for j, currCost in ipairs(obstacle.currencyCosts) do
local shortID = nil
if currCost.id == 'melvorD:GP' then
shortID = 'GP'
elseif currCost.id == 'melvorD:SlayerCoins' then
shortID = 'SC'
elseif currCost.id == 'melvorItA:AbyssalPieces' then
shortID = 'AP'
elseif currCost.id == 'melvorItA:AbyssalSlayerCoins' then
shortID = 'ASC'
end
if shortID ~= nil then
costs[shortID] = currCost.quantity
end
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.getObstacleRequirementsRealm(obstacle)
for skill, req in pairs(requirements) do
local icon
if req.isAbyssal then
icon = Icons._SkillReq(skill, req.level, nil, 'melvorItA:Abyssal')
else
icon = Icons._SkillReq(skill, req.level)
end
table.insert(resultPart, icon)
end
 
return table.concat(resultPart, '<br/>')
end
end


function p.getObstacleCourseTable(frame)
function p.getObstacleCourseTable(frame)
  local result = ''
local args = frame.args ~= nil and frame.args or frame
local realmName = args.realm
local realmID = nil
if realmName ~= nil and realmName ~= '' then
local realm = GameData.getEntityByName('realms', realmName)
if realm == nil then
return Shared.printError('No such realm: ' .. realmName)
end
realmID = realm.id
end
local currName = 'GP'
if realmID == 'melvorItA:Abyssal' then
currName = 'AP'
end
local result = ''


  result = '{| class="wikitable sortable stickyHeader"'
result = '{| class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!Slot!!Name!!XP!!GP!!Time'--!!XP/s!!GP/s
result = result..'\r\n!Slot!!Name!!XP!!'..currName..'!!Time!!XP/s!!'..currName..'/s!!Bonuses!!Requirements!!Cost'
  result = result..'!!Bonuses!!Requirements!!Cost'


  local catLog = {}
local catLog = {}
  local Obstacles = Shared.clone(SkillData.Agility.Obstacles)
local obstacles = p.getObstacles(
  table.sort(Obstacles, function(a, b) return (a.category == b.category and a.id < b.id) or a.category < b.category end)
function(obst)
return realmID == nil or Skills.getRecipeRealm(obst) == realmID
end
)
table.sort(obstacles, function(a, b) return a.category < b.category end)


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


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


    --After the name & category, doing XP, GP, Time, and rates
--After the name & category, doing XP, GP, Time, and rates
    local XP = obst.completionBonuses.xp
local XP = obst.baseExperience
    local GP = obst.completionBonuses.gp
if XP == 0 then
    local Time = obst.interval / 1000
XP = obst.baseAbyssalExperience
    result = result..'||'..XP..'||data-sort-value="'..GP..'"|'..Icons.GP(GP)
end
    result = result..'||data-sort-value="'..Time..'"|'..Shared.timeString(Time, true)
local GP = obst.gpReward
    --result = result..'||'..Shared.round(XP / Time, 2, 2)
local Time = obst.baseInterval / 1000
    --result = result..'||data-sort-value="'..GP/Time..'"|'..Icons.GP(Shared.round(GP/Time, 2, 2))
local costString = Common.getCostString({
items = obst.itemCosts,
currencies = obst.currencyCosts
})
local rewardString = Common.getCostString({
items = obst.itemRewards,
currencies = obst.currencyRewards
})
local costVal = (obst.currencyCosts ~= nil and obst.currencyCosts[1].quantity or 0)
local rewardVal = (obst.currencyRewards ~= nil and obst.currencyRewards[1].quantity or 0)


    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.tableCount(bonuses) == 0 then
      table.insert(bonuses, '<span style="color:red">None :(</span>')
    end
    result = result..'||'..table.concat(bonuses, '<br/>')


    --Grabbing requirements to create
result = result..'||'..XP..'||data-sort-value="'..rewardVal..'"|'..rewardString
    result = result..'||'
result = result..'||data-sort-value="'..Time..'"|'..Shared.timeString(Time, true)
    if obst.category > 0 then
-- Readded XP/Time and GP/Time (previously commented out)
      result = result..Icons._SkillReq('Agility', obst.category * 10)
result = result..'||'..Num.round(XP / Time, 2, 2)
    end
result = result..'||data-sort-value="'..rewardVal/Time..'"|'.. Icons._Currency(currName, Num.round(rewardVal/Time, 2, 2))
    if obst.requirements ~= nil and obst.requirements.skillLevel ~= nil then
      for j, skillReq in ipairs(obst.requirements.skillLevel) do
        result = result..'<br/>'..Icons._SkillReq(Constants.getSkillName(skillReq[1]), skillReq[2])
      end
    end


    --Finally, the cost
local bonuses = {}
    local costs = {}
--After that, adding the bonuses
    if obst.cost.gp > 0 then table.insert(costs, Icons.GP(obst.cost.gp)) end
local modText = Modifiers.getModifiersText(obst.modifiers, true, false, 10)
    if obst.cost.slayerCoins > 0 then table.insert(costs, Icons.SC(obst.cost.slayerCoins)) end
if modText == '' then
    for j, itemCost in ipairs(obst.cost.items) do
modText = '<span style="text-negative">None :(</span>'
      local item = Items.getItemByID(itemCost[1])
end
      table.insert(costs, Icons.Icon({item.name, type='item', qty = itemCost[2], notext=true}))
result = result..'||'..modText
    end
    result = result..'|| data-sort-value="'..obst.cost.gp..'"|'..table.concat(costs, '<br/>')
  end


  result = result..'\r\n|}'
--Grabbing requirements to create
result = result..'|| ' .. p._getObstacleRequirements(obst)


  return result
--Finally, the cost
result = result..'|| data-sort-value="'..costVal..'"|'..costString
end
 
result = result..'\r\n|}'
 
return result
end
end


function p.getPassivePillarTable(frame)
function p.getPassivePillarTable(frame)
  local result = ''
local args = frame.args ~= nil and frame.args or frame
local realmName = args.realm
local realmID = nil
if realmName ~= nil and realmName ~= '' then
local realm = GameData.getEntityByName('realms', realmName)
if realm == nil then
return Shared.printError('No such realm: ' .. realmName)
end
realmID = realm.id
end
 
local result = ''


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


  for i, pill in ipairs(SkillData.Agility.Pillars) do
local pillars = p.getPillars(
    result = result..'\r\n|-'
function(pill)
    result = result..'\r\n|'..pill.name
return realmID == nil or Skills.getRecipeRealm(pill) == realmID
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
--After that, adding the bonuses
    local bonuses = {}
local modText = Modifiers.getModifiersText(pill.modifiers, true, false, 10)
    for bonusName, bonusValue in pairs(pill.modifiers) do
if modText == '' then
      table.insert(bonuses, Constants._getModifierText(bonusName, bonusValue))
modText = '<span style="text-negative">None :(</span>'
    end
end
    if Shared.tableCount(bonuses) == 0 then
result = result..'||'..modText
      table.insert(bonuses, '<span style="color:red">None :(</span>')
    end
    result = result..'||'..table.concat(bonuses, '<br/>')


    --Finally, the cost
--Finally, the cost
    local costs = {}
local costString = Common.getCostString({
    if pill.cost.gp > 0 then table.insert(costs, Icons.GP(pill.cost.gp)) end
items = pill.itemCosts,
    if pill.cost.slayerCoins > 0 then table.insert(costs, Icons.SC(pill.cost.slayerCoins)) end
currencies = pill.currencyCosts
    for j, itemCost in ipairs(pill.cost.items) do
})
      local item = Items.getItemByID(itemCost[1])
local costVal = (pill.currencyCosts ~= nil and pill.currencyCosts[1].quantity or 0)
      table.insert(costs, Icons.Icon({item.name, type='item', qty = itemCost[2], notext=true}))
result = result..'|| data-sort-value="'..costVal..'"|'.. costString
    end
end
    result = result..'|| data-sort-value="'..pill.cost.gp..'"|'..table.concat(costs, '<br/>')
  end


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


  return result
return result
end
end


function p.getObstaclesForItem(itemID)
function p.getObstaclesForItem(itemID)
  local result = {}
local costFunc =
  for i, obst in ipairs(SkillData.Agility.Obstacles) do
function(obst)
    for j, costLine in ipairs(obst.cost.items) do
for i, itemCost in ipairs(obst.itemCosts) do
      if costLine[1] == itemID then
if itemCost.id == itemID then
        table.insert(result, obst)
return true
      end
end
    end
end
  end
return false
end
local pillars = p.getPillars(costFunc)


  for i, obst in ipairs(SkillData.Agility.Pillars) do
local result = p.getObstacles(costFunc)
    for j, costLine in ipairs(obst.cost.items) do
if result == nil or Shared.tableIsEmpty(result) then
      if costLine[1] == itemID then
result = pillars
        table.insert(result, obst)
else
      end
for i, pillar in ipairs(pillars) do
    end
table.insert(result, pillar)
  end
end
end


  return result
return result
end
end


return p
return p

Latest revision as of 17:58, 22 July 2024

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 Common = require('Module:Common')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Modifiers = require('Module:Modifiers')
local Skills = require('Module:Skills')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Num = require('Module:Number')

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)
	return GameData.getEntities(SkillData.Agility.pillars, checkFunc)
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 ap =   Num.clamp((costReduction['AP'] or 0), 0, 100) / 100
	local asc =   Num.clamp((costReduction['ASC'] 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
	if ap > 0 and itemCosts['AP'] then
		itemCosts['AP'] = math.ceil(itemCosts['AP'] * (1 - ap))
	end
	if asc > 0 and itemCosts['ASC'] then
		itemCosts['ASC'] = math.ceil(itemCosts['ASC'] * (1 - asc))
	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 realmRequirements = p.getObstacleRequirementsRealm(obstacle)
	local levelRequirements = {}
	
	for skillName, skillReq in pairs(realmRequirements) do
		levelRequirements[skillName] = skillReq.level
	end
	
	return levelRequirements
end

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

	-- 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] = { 
					level = skillReq.level, 
					isAbyssal = skillReq.type == 'AbyssalLevel' 
				}
			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 = {}

	for j, currCost in ipairs(obstacle.currencyCosts) do
		local shortID = nil
		if currCost.id == 'melvorD:GP' then
			shortID = 'GP'
		elseif currCost.id == 'melvorD:SlayerCoins' then
			shortID = 'SC'
		elseif currCost.id == 'melvorItA:AbyssalPieces' then
			shortID = 'AP'
		elseif currCost.id == 'melvorItA:AbyssalSlayerCoins' then
			shortID = 'ASC'
		end
		if shortID ~= nil then
			costs[shortID] = currCost.quantity
		end
	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.getObstacleRequirementsRealm(obstacle)
	
	for skill, req in pairs(requirements) do
		local icon
		if req.isAbyssal then
			icon = Icons._SkillReq(skill, req.level, nil, 'melvorItA:Abyssal')
		else
			icon = Icons._SkillReq(skill, req.level)
		end
		table.insert(resultPart, icon)
	end

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

function p.getObstacleCourseTable(frame)
	local args = frame.args ~= nil and frame.args or frame
	local realmName = args.realm
	local realmID = nil
	if realmName ~= nil and realmName ~= '' then
		local realm = GameData.getEntityByName('realms', realmName)
		if realm == nil then
			return Shared.printError('No such realm: ' .. realmName)
		end
		realmID = realm.id
	end
	local currName = 'GP'
	if realmID == 'melvorItA:Abyssal' then
		currName = 'AP'
	end
	
	local result = ''

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

	local catLog = {}
	local obstacles = p.getObstacles(
		function(obst)
			return realmID == nil or Skills.getRecipeRealm(obst) == realmID
		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
		if XP == 0 then
			XP = obst.baseAbyssalExperience
		end
		local GP = obst.gpReward
		local Time = obst.baseInterval / 1000
		local costString = Common.getCostString({
			items = obst.itemCosts,
			currencies = obst.currencyCosts
		})
		local rewardString = Common.getCostString({
			items = obst.itemRewards,
			currencies = obst.currencyRewards
		})
		local costVal = (obst.currencyCosts ~= nil and obst.currencyCosts[1].quantity or 0)
		local rewardVal = (obst.currencyRewards ~= nil and obst.currencyRewards[1].quantity or 0)


		result = result..'||'..XP..'||data-sort-value="'..rewardVal..'"|'..rewardString
		result = result..'||data-sort-value="'..Time..'"|'..Shared.timeString(Time, true)
		-- Readded XP/Time and GP/Time (previously commented out)
		result = result..'||'..Num.round(XP / Time, 2, 2)
		result = result..'||data-sort-value="'..rewardVal/Time..'"|'.. Icons._Currency(currName, Num.round(rewardVal/Time, 2, 2))

		local bonuses = {}
		--After that, adding the bonuses
		local modText = Modifiers.getModifiersText(obst.modifiers, true, false, 10)
		if modText == '' then
			modText = '<span style="text-negative">None :(</span>'
		end
		result = result..'||'..modText

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

		--Finally, the cost
		result = result..'|| data-sort-value="'..costVal..'"|'..costString
	end

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

	return result
end

function p.getPassivePillarTable(frame)
	local args = frame.args ~= nil and frame.args or frame
	local realmName = args.realm
	local realmID = nil
	if realmName ~= nil and realmName ~= '' then
		local realm = GameData.getEntityByName('realms', realmName)
		if realm == nil then
			return Shared.printError('No such realm: ' .. realmName)
		end
		realmID = realm.id
	end

	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(pill)
			return realmID == nil or Skills.getRecipeRealm(pill) == realmID
		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 modText = Modifiers.getModifiersText(pill.modifiers, true, false, 10)
		if modText == '' then
			modText = '<span style="text-negative">None :(</span>'
		end
		result = result..'||'..modText

		--Finally, the cost
		local costString = Common.getCostString({
			items = pill.itemCosts,
			currencies = pill.currencyCosts
		})
		local costVal = (pill.currencyCosts ~= nil and pill.currencyCosts[1].quantity or 0)
		result = result..'|| data-sort-value="'..costVal..'"|'.. costString
	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