Module:ModifierTables: Difference between revisions

From Melvor Idle
(Created initial pass at this)
(35 intermediate revisions by 3 users not shown)
Line 1: Line 1:
--Module that constructs tables for all things that can affect Player Modifiers
--Module that constructs tables for all things that can affect Player Modifiers
--This includes Agility, Equipment, and Pets right now
--This includes Agility, Equipment, Pets, Prayers, and Constellations right now


local p = {}
local p = {}
Line 8: Line 8:
local Pets = require('Module:Pets')
local Pets = require('Module:Pets')
local Items = require('Module:Items')
local Items = require('Module:Items')
local Skills = require('Module:Skills')
local Agility = require('Module:Skills/Agility')
local Agility = require('Module:Skills/Agility')
local Prayer = require('Module:Prayer')
local Shop = require('Module:Shop')
local Shop = require('Module:Shop')
local Icons = require('Module:Icons')


--First up, functions to get all the things in a category that have a given modifier:
--First up, functions to get all the things in a category that have a given modifier:
function p.getModifierValue(modifiers, modifier, skill, getOpposites)
function p.getModifierValue(modifiers, modifier, skill, getOpposites)
  --Sometimes nil modifier sets will get here, which is fine. Just return 0 immediately
--Sometimes nil modifier sets will get here, which is fine. Just return 0 immediately
  if modifiers == nil then
if modifiers == nil then
    return 0
return 0
  end
end
 
  --Make sure we have the skillID and not the name
  if skill == '' then
    skill = nil
  elseif type(skill) == 'string' then
    skill = Constants.getSkillID(skill)
  end


  --By default, attempt to add the increased and decreased prefixes to the modifier
--Make sure we have the skillID and not the name
  --But if getOpposites is false, only look for an exact match
if skill == '' then
  local increaseMod, decreaseMod = '', ''
skill = nil
  if getOpposites == nil or getOpposites then
elseif type(skill) == 'string' then
    increaseMod = 'increased'..modifier
skill = Constants.getSkillID(skill)
    decreaseMod = 'decreased'..modifier
end
  else
    increaseMod = modifier
  end


  if not p.hasLogged then
--By default, attempt to add the increased and decreased prefixes to the modifier
    mw.log(increaseMod..', '..decreaseMod)
--But if getOpposites is false, only look for an exact match
    p.hasLogged = true
local increaseMod, decreaseMod = '', ''
  end
if getOpposites == nil or getOpposites then
  local increaseVal, decreaseVal = 0, 0
increaseMod = 'increased'..modifier
  if modifiers[increaseMod] ~= nil and modifiers[increaseMod] ~= nil then
decreaseMod = 'decreased'..modifier
    if type(modifiers[increaseMod]) == 'table' then
else
      for i, subVal in Shared.skpairs(modifiers[increaseMod]) do
increaseMod = modifier
        if subVal[1] == skill then
end
          increaseVal = subVal[2]
        end
      end
    else
      increaseVal = modifiers[increaseMod]
    end
  end


  if modifiers[decreaseMod] ~= nil and modifiers[decreaseMod] ~= nil then
local increaseVal, decreaseVal = 0, 0
    if type(modifiers[decreaseMod]) == 'table' then
if modifiers[increaseMod] ~= nil and modifiers[increaseMod] ~= nil then
      for i, subVal in Shared.skpairs(modifiers[decreaseMod]) do
if type(modifiers[increaseMod]) == 'table' then
        if subVal[1] == skill then
for i, subVal in Shared.skpairs(modifiers[increaseMod]) do
          decreaseVal = subVal[2]
if subVal[1] == skill then
        end
increaseVal = subVal[2]
      end
elseif skill == nil or skill == '' then
    else
increaseVal = increaseVal + subVal[2]
      decreaseVal = modifiers[decreaseMod]
end
    end
end
  end
else
increaseVal = modifiers[increaseMod]
end
end


  return increaseVal - decreaseVal
if modifiers[decreaseMod] ~= nil and modifiers[decreaseMod] ~= nil then
if type(modifiers[decreaseMod]) == 'table' then
for i, subVal in Shared.skpairs(modifiers[decreaseMod]) do
if subVal[1] == skill then
decreaseVal = subVal[2]
elseif skill == nil or skill == '' then
decreaseVal = decreaseVal + subVal[2]
end
end
else
decreaseVal = modifiers[decreaseMod]
end
end
 
return increaseVal - decreaseVal
end
 
function p.getItemsWithModifier(modifiers, skill, getOpposites)
if type(modifiers) == 'string' then
modifiers = {modifiers}
end
local itemList = Items.getItems(
function(item)
if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then
return false
end
for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(item.modifiers, mod, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return itemList
end
end


function p.getItemsWithModifier(modifier, skill, getOpposites)
function p.getObstaclesWithModifier(modifiers, skill, getOpposites)
  local itemList = Items.getItems(
if type(modifiers) == 'string' then
        function(item)
modifiers = {modifiers}
          return p.getModifierValue(item.modifiers, modifier, skill, getOpposites) ~= 0
end
        end)
local obstList = Agility.getObstacles(
  return itemList
function(obst)
for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(obst.modifiers, mod, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return obstList
end
end


function p.getObstaclesWithModifier(modifier, skill, getOpposites)
function p.getConstellationsWithModifier(modifiers, skill, getOpposites)
  local obstList = Agility.getObstacles(
if type(modifiers) == 'string' then
        function(obst)
modifiers = {modifiers}
          return p.getModifierValue(obst.modifiers, modifier, skill, getOpposites) ~= 0
end
        end)
local consList = Skills.getConstellations(
  return obstList
function(cons)
local consMods = Skills._buildAstrologyModifierArray(cons, 1, true, true, true, true)
for i, modifier in ipairs(modifiers) do
if p.getModifierValue(consMods, modifier, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return consList
end
end


function p.getPetsWithModifier(modifier, skill, getOpposites)
function p.getPillarsWithModifier(modifiers, skill, getOpposites)
  local petList = Pets.getPets(
if type(modifiers) == 'string' then
        function(pet)
modifiers = {modifiers}
          return p.getModifierValue(pet.modifiers, modifier, skill, getOpposites) ~= 0
end
        end)
local pillarList = Agility.getPillars(
  return petList
function(pillar)
for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(pillar.modifiers, mod, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return pillarList
end
end


function p.getUpgradesWithModifier(modifier, skill, getOpposites)
function p.getPetsWithModifier(modifiers, skill, getOpposites)
  local upgradeList = Shop.getPurchases(
if type(modifiers) == 'string' then
        function(purchase)
modifiers = {modifiers}
          return p.getModifierValue(purchase.contains.modifiers, modifier, skill, getOpposites) ~= 0
end
        end)
local petList = Pets.getPets(
return upgradeList
function(pet)
for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(pet.modifiers, mod, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return petList
end
 
function p.getPrayersWithModifier(modifiers, skill, getOpposites)
if type(modifiers) == 'string' then
modifiers = {modifiers}
end
local prayerList = Prayer.getPrayers(
function(prayer)
for i, mod in ipairs(modifiers) do
if p.getModifierValue(prayer.modifiers, mod, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return prayerList
end
 
function p.getUpgradesWithModifier(modifiers, skill, getOpposites)
if type(modifiers) == 'string' then
modifiers = {modifiers}
end
local upgradeList = Shop.getPurchases(
function(category, purchase)
if category == 'GolbinRaid' then
return false
end
for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(purchase.contains.modifiers, mod, skill, getOpposites) ~= 0 then
return true
end
end
return false
end)
return upgradeList
end
 
function p._getModifierTable(modifiers, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
local modifierNames = {}
if type(modifiers) == 'string' then
modifiers = {modifiers}
end
for i, modifier in pairs(modifiers) do
if getOpposites then
table.insert(modifierNames, 'increased'..modifier)
table.insert(modifierNames, 'decreased'..modifier)
else
table.insert(modifierNames, modifier)
end
end
 
local hasOtherModifiers = false
local modifierCount = Shared.tableCount(modifiers)
 
if skill == '' then
skill = nil
elseif type(skill) == 'string' then
skill = Constants.getSkillID(skill)
end
 
local getModText =
function(modifiers)
local modTextArray = { ["visible"] = {}, ["overflow"] = {} }
local otherModCount = 0
local mainModText = {}
for modName, modValue in Shared.skpairs(modifiers) do
if Shared.contains(modifierNames, modName) then
if type(modValue) == 'table' and type(modValue[1]) == 'table' then
for j, subVal in ipairs(modValue) do
if subVal[1] == skill or skill == nil or skill == '' then
table.insert(mainModText, Constants._getModifierText(modName, subVal))
else
otherModCount = otherModCount + 1
local key = ((maxOtherMods == nil or otherModCount <= maxOtherMods) and 'visible') or 'overflow'
table.insert(modTextArray[key], Constants._getModifierText(modName, subVal))
end
end
else
table.insert(mainModText, Constants._getModifierText(modName, modValue))
end
else
modValue = (type(modValue) == 'table' and type(modValue[1]) == 'table' and modValue or {modValue})
for j, subValue in ipairs(modValue) do
otherModCount = otherModCount + 1
local key = ((maxOtherMods == nil or otherModCount <= maxOtherMods) and 'visible') or 'overflow'
table.insert(modTextArray[key], Constants._getModifierText(modName, subValue))
end
end
end
 
local overflowModCount = Shared.tableCount(modTextArray['overflow'])
if overflowModCount == 1 then
table.insert(modTextArray['visible'], modTextArray['overflow'][1])
end
local otherModText = {table.concat(modTextArray['visible'], '<br/>')}
 
if overflowModCount > 1 then
-- Number of other modifiers for the object exceed the specified maximum
table.insert(otherModText, '<br/><span class="mw-collapsible mw-collapsed" ')
table.insert(otherModText, 'data-expandtext="Show ' .. Shared.formatnum(overflowModCount) .. ' more modifiers", data-collapsetext="Hide">')
table.insert(otherModText, table.concat(modTextArray['overflow'], '<br/>') .. '</span>')
end
return table.concat(mainModText, '<br/>'), table.concat(otherModText)
end
 
local tableArray = {}
--Going through each type of thing to add to the array
local itemList = p.getItemsWithModifier(modifiers, skill, getOpposites)
for i, item in Shared.skpairs(itemList) do
local row = {}
row.name = item.name
row.icon = Icons.Icon({item.name, type='item'})
row.type = 'Item'
--For equipment, show the slot they go in
if item.validSlots ~= nil then
row.type = row.type..' ('..table.concat(item.validSlots, ', ')..')'
end
local totalVal = 0
for i, mod in pairs(modifiers) do
totalVal = totalVal + p.getModifierValue(item.modifiers, mod, skill, getOpposites)
end
row.val = totalVal
 
row.modifierText, row.otherModifiers = getModText(item.modifiers)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local petList = p.getPetsWithModifier(modifiers, skill, getOpposites)
for i, pet in Shared.skpairs(petList) do
local row = {}
row.name = pet.name
row.icon = Icons.Icon({pet.name, type='pet'})
row.type = '[[Pets|Pet]]'
local totalVal = 0
for i, mod in pairs(modifiers) do
totalVal = totalVal + p.getModifierValue(pet.modifiers, mod, skill, getOpposites)
end
row.val = totalVal
 
row.modifierText, row.otherModifiers = getModText(pet.modifiers)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local obstList = p.getObstaclesWithModifier(modifiers, skill, getOpposites)
for i, obst in Shared.skpairs(obstList) do
local row = {}
row.name = obst.name
row.icon = Icons.Icon({'Agility', obst.name, type='skill'})
row.type = '[[Agility#Obstacles|Agility Obstacle '..tostring(tonumber(obst.category)+1)..']]'
local totalVal = 0
for i, mod in pairs(modifiers) do
totalVal = totalVal + p.getModifierValue(obst.modifiers, mod, skill, getOpposites)
end
row.val = totalVal
 
row.modifierText, row.otherModifiers = getModText(obst.modifiers)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local pillarList = p.getPillarsWithModifier(modifiers, skill, getOpposites)
for i, pillar in Shared.skpairs(pillarList) do
local row = {}
row.name = pillar.name
row.icon = Icons.Icon({'Agility', pillar.name, type='skill'})
row.type = '[[Agility#Passive Pillars|Agility Pillar]]'
local totalVal = 0
for i, mod in pairs(modifiers) do
totalVal = totalVal + p.getModifierValue(pillar.modifiers, mod, skill, getOpposites)
end
row.val = totalVal
 
row.modifierText, row.otherModifiers = getModText(pillar.modifiers)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local prayerList = p.getPrayersWithModifier(modifiers, skill, getOpposites)
for i, prayer in ipairs(prayerList) do
local row = {}
row.name = prayer.name
row.icon = Icons.Icon({prayer.name, type='prayer'})
row.type = [[Prayer]]
local totalVal = 0
for i, mod in ipairs(modifiers) do
totalVal = totalVal + p.getModifierValue(prayer.modifiers, mod, skill, getOpposites)
end
row.val = totalVal
 
row.modifierText, row.otherModifiers = getModText(prayer.modifiers)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local upgradeList = p.getUpgradesWithModifier(modifiers, skill, getOpposites)
for i, upgrade in Shared.skpairs(upgradeList) do
local row = {}
row.name = upgrade.name
row.icon = Icons.Icon({upgrade.name, type='upgrade'})
row.type = '[[Shop|Upgrade]]'
local totalVal = 0
for i, mod in pairs(modifiers) do
totalVal = totalVal + p.getModifierValue(upgrade.contains.modifiers, mod, skill, getOpposites)
end
row.val = totalVal
 
row.modifierText, row.otherModifiers = getModText(upgrade.contains.modifiers)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local constellationList = p.getConstellationsWithModifier(modifiers, skill, getOpposites)
for i, cons in ipairs(constellationList) do
local row = {}
row.name = cons.name
row.icon = Icons.Icon({cons.name, type='constellation'})
row.type = '[[Astrology#Constellations|Constellation]]'
row.val = 15 -- Assume highest possible, the range is 1 to 15 inclusive
 
local modList = Skills._buildAstrologyModifierArray(cons, {1, 15}, true, true, true, true)
row.modifierText, row.otherModifiers = getModText(modList)
 
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
hasOtherModifiers = true
end
 
table.insert(tableArray, row)
end
 
local result = '{| class="wikitable sortable stickyHeader"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n!Source!!Type!!'..columnName
if hasOtherModifiers and displayOtherMods then result = result..'!!Other Modifiers' end
 
--Sort by value if only one modifier was passed in
--Otherwise sort alphabetically by type, then name
table.sort(tableArray, function(a, b)
if modifierCount == 1 and a.val ~= b.val then
return a.val > b.val
elseif a.type ~= b.type then
return a.type < b.type
else
return a.name < b.name
end
end)
for i, row in Shared.skpairs(tableArray) do
result = result..'\r\n|-'
result = result..'\r\n|data-sort-value="'..row.name..'"|'..row.icon
result = result..'||'..row.type..'||data-sort-value="'..row.val..'"|'..row.modifierText
if hasOtherModifiers and displayOtherMods then
result = result..'||'..row.otherModifiers
end
end
 
result = result..'\r\n|}'
return result
end
 
function p.getModifierTable(frame)
local modifier = frame.args ~= nil and frame.args[1] or frame[1]
local skill = frame.args ~= nil and frame.args.skill or frame.skill
local columnName = frame.args ~= nil and frame.args[2] or frame[2]
local getOpposites = frame.args ~= nil and frame.args[3] or frame[3]
local displayOtherMods = frame.args ~= nil and frame.args.displayOtherMods or frame.displayOtherMods
local maxOtherMods = frame.args ~= nil and tonumber(frame.args.maxOtherMods) or 5
 
if Shared.contains(modifier, ',') then
modifier = Shared.splitString(modifier, ',')
end
 
if getOpposites ~= nil then
getOpposites = string.upper(getOpposites) ~= 'FALSE'
else
getOpposites = true
end
 
if displayOtherMods ~= nil then
displayOtherMods = string.upper(displayOtherMods) ~= 'FALSE'
else
displayOtherMods = true
end
 
return p._getModifierTable(modifier, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
end
end


return p
return p

Revision as of 14:07, 18 April 2022

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

--Module that constructs tables for all things that can affect Player Modifiers
--This includes Agility, Equipment, Pets, Prayers, and Constellations right now

local p = {}

local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Pets = require('Module:Pets')
local Items = require('Module:Items')
local Skills = require('Module:Skills')
local Agility = require('Module:Skills/Agility')
local Prayer = require('Module:Prayer')
local Shop = require('Module:Shop')
local Icons = require('Module:Icons')

--First up, functions to get all the things in a category that have a given modifier:
function p.getModifierValue(modifiers, modifier, skill, getOpposites)
	--Sometimes nil modifier sets will get here, which is fine. Just return 0 immediately
	if modifiers == nil then
		return 0
	end

	--Make sure we have the skillID and not the name
	if skill == '' then
		skill = nil
	elseif type(skill) == 'string' then
		skill = Constants.getSkillID(skill)
	end

	--By default, attempt to add the increased and decreased prefixes to the modifier
	--But if getOpposites is false, only look for an exact match
	local increaseMod, decreaseMod = '', ''
	if getOpposites == nil or getOpposites then
		increaseMod = 'increased'..modifier
		decreaseMod = 'decreased'..modifier
	else
		increaseMod = modifier
	end

	local increaseVal, decreaseVal = 0, 0
	if modifiers[increaseMod] ~= nil and modifiers[increaseMod] ~= nil then
		if type(modifiers[increaseMod]) == 'table' then
			for i, subVal in Shared.skpairs(modifiers[increaseMod]) do
				if subVal[1] == skill then
					increaseVal = subVal[2]
				elseif skill == nil or skill == '' then
					increaseVal = increaseVal + subVal[2]
				end
			end
		else
			increaseVal = modifiers[increaseMod]
		end
	end

	if modifiers[decreaseMod] ~= nil and modifiers[decreaseMod] ~= nil then
		if type(modifiers[decreaseMod]) == 'table' then
			for i, subVal in Shared.skpairs(modifiers[decreaseMod]) do
				if subVal[1] == skill then
					decreaseVal = subVal[2]
				elseif skill == nil or skill == '' then
					decreaseVal = decreaseVal + subVal[2]
				end
			end
		else
			decreaseVal = modifiers[decreaseMod]
		end
	end

	return increaseVal - decreaseVal
end

function p.getItemsWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local itemList = Items.getItems(
		function(item)
			if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then
				return false
			end
			for i, mod in Shared.skpairs(modifiers) do
				if p.getModifierValue(item.modifiers, mod, skill, getOpposites) ~= 0 then
					return true
				end
			end
			return false
		end)
	return itemList
end

function p.getObstaclesWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local obstList = Agility.getObstacles(
		function(obst)
			for i, mod in Shared.skpairs(modifiers) do
				if p.getModifierValue(obst.modifiers, mod, skill, getOpposites) ~= 0 then
					return true
				end
			end
			return false
		end)
	return obstList
end

function p.getConstellationsWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local consList = Skills.getConstellations(
			function(cons)
				local consMods = Skills._buildAstrologyModifierArray(cons, 1, true, true, true, true)
				for i, modifier in ipairs(modifiers) do
					if p.getModifierValue(consMods, modifier, skill, getOpposites) ~= 0 then
						return true
					end
				end
				return false
			end)
	return consList
end

function p.getPillarsWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local pillarList = Agility.getPillars(
		function(pillar)
			for i, mod in Shared.skpairs(modifiers) do
				if p.getModifierValue(pillar.modifiers, mod, skill, getOpposites) ~= 0 then
					return true
				end
			end
			return false
		end)
	return pillarList
end

function p.getPetsWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local petList = Pets.getPets(
		function(pet)
			for i, mod in Shared.skpairs(modifiers) do
				if p.getModifierValue(pet.modifiers, mod, skill, getOpposites) ~= 0 then
					return true
				end
			end
			return false
		end)
	return petList
end

function p.getPrayersWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local prayerList = Prayer.getPrayers(
		function(prayer)
			for i, mod in ipairs(modifiers) do
				if p.getModifierValue(prayer.modifiers, mod, skill, getOpposites) ~= 0 then
					return true
				end
			end
			return false
		end)
	return prayerList
end

function p.getUpgradesWithModifier(modifiers, skill, getOpposites)
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	local upgradeList = Shop.getPurchases(
		function(category, purchase)
			if category == 'GolbinRaid' then
				return false
			end
			for i, mod in Shared.skpairs(modifiers) do
				if p.getModifierValue(purchase.contains.modifiers, mod, skill, getOpposites) ~= 0 then
					return true
				end
			end
			return false
		end)
	return upgradeList
end

function p._getModifierTable(modifiers, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
	local modifierNames = {}
	if type(modifiers) == 'string' then
		modifiers = {modifiers}
	end
	for i, modifier in pairs(modifiers) do
		if getOpposites then
			table.insert(modifierNames, 'increased'..modifier)
			table.insert(modifierNames, 'decreased'..modifier)
		else
			table.insert(modifierNames, modifier)
		end
	end

	local hasOtherModifiers = false
	local modifierCount = Shared.tableCount(modifiers)

	if skill == '' then
		skill = nil
	elseif type(skill) == 'string' then
		skill = Constants.getSkillID(skill)
	end

	local getModText =
		function(modifiers)
			local modTextArray = { ["visible"] = {}, ["overflow"] = {} }
			local otherModCount = 0
			local mainModText = {}
			for modName, modValue in Shared.skpairs(modifiers) do
				if Shared.contains(modifierNames, modName) then
					if type(modValue) == 'table' and type(modValue[1]) == 'table' then
						for j, subVal in ipairs(modValue) do
							if subVal[1] == skill or skill == nil or skill == '' then
								table.insert(mainModText, Constants._getModifierText(modName, subVal))
							else
								otherModCount = otherModCount + 1
								local key = ((maxOtherMods == nil or otherModCount <= maxOtherMods) and 'visible') or 'overflow'
								table.insert(modTextArray[key], Constants._getModifierText(modName, subVal))
							end
						end
					else
						table.insert(mainModText, Constants._getModifierText(modName, modValue))
					end
				else
					modValue = (type(modValue) == 'table' and type(modValue[1]) == 'table' and modValue or {modValue})
					for j, subValue in ipairs(modValue) do
						otherModCount = otherModCount + 1
						local key = ((maxOtherMods == nil or otherModCount <= maxOtherMods) and 'visible') or 'overflow'
						table.insert(modTextArray[key], Constants._getModifierText(modName, subValue))
					end
				end
			end

			local overflowModCount = Shared.tableCount(modTextArray['overflow'])
			if overflowModCount == 1 then
				table.insert(modTextArray['visible'], modTextArray['overflow'][1])
			end
			local otherModText = {table.concat(modTextArray['visible'], '<br/>')}

			if overflowModCount > 1 then
				-- Number of other modifiers for the object exceed the specified maximum
				table.insert(otherModText, '<br/><span class="mw-collapsible mw-collapsed" ')
				table.insert(otherModText, 'data-expandtext="Show ' .. Shared.formatnum(overflowModCount) .. ' more modifiers", data-collapsetext="Hide">')
				table.insert(otherModText, table.concat(modTextArray['overflow'], '<br/>') .. '</span>')
			end
			return table.concat(mainModText, '<br/>'), table.concat(otherModText)
		end

	local tableArray = {}
	--Going through each type of thing to add to the array
	local itemList = p.getItemsWithModifier(modifiers, skill, getOpposites)
	for i, item in Shared.skpairs(itemList) do
		local row = {}
		row.name = item.name
		row.icon = Icons.Icon({item.name, type='item'})
		row.type = 'Item'
		--For equipment, show the slot they go in
		if item.validSlots ~= nil then
			row.type = row.type..' ('..table.concat(item.validSlots, ', ')..')'
		end
		local totalVal = 0
		for i, mod in pairs(modifiers) do
			totalVal = totalVal + p.getModifierValue(item.modifiers, mod, skill, getOpposites)
		end
		row.val = totalVal

		row.modifierText, row.otherModifiers = getModText(item.modifiers)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local petList = p.getPetsWithModifier(modifiers, skill, getOpposites)
	for i, pet in Shared.skpairs(petList) do
		local row = {}
		row.name = pet.name
		row.icon = Icons.Icon({pet.name, type='pet'})
		row.type = '[[Pets|Pet]]'
		local totalVal = 0
		for i, mod in pairs(modifiers) do
			totalVal = totalVal + p.getModifierValue(pet.modifiers, mod, skill, getOpposites)
		end
		row.val = totalVal

		row.modifierText, row.otherModifiers = getModText(pet.modifiers)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local obstList = p.getObstaclesWithModifier(modifiers, skill, getOpposites)
	for i, obst in Shared.skpairs(obstList) do
		local row = {}
		row.name = obst.name
		row.icon = Icons.Icon({'Agility', obst.name, type='skill'})
		row.type = '[[Agility#Obstacles|Agility Obstacle '..tostring(tonumber(obst.category)+1)..']]'
		local totalVal = 0
		for i, mod in pairs(modifiers) do
			totalVal = totalVal + p.getModifierValue(obst.modifiers, mod, skill, getOpposites)
		end
		row.val = totalVal

		row.modifierText, row.otherModifiers = getModText(obst.modifiers)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local pillarList = p.getPillarsWithModifier(modifiers, skill, getOpposites)
	for i, pillar in Shared.skpairs(pillarList) do
		local row = {}
		row.name = pillar.name
		row.icon = Icons.Icon({'Agility', pillar.name, type='skill'})
		row.type = '[[Agility#Passive Pillars|Agility Pillar]]'
		local totalVal = 0
		for i, mod in pairs(modifiers) do
			totalVal = totalVal + p.getModifierValue(pillar.modifiers, mod, skill, getOpposites)
		end
		row.val = totalVal

		row.modifierText, row.otherModifiers = getModText(pillar.modifiers)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local prayerList = p.getPrayersWithModifier(modifiers, skill, getOpposites)
	for i, prayer in ipairs(prayerList) do
		local row = {}
		row.name = prayer.name
		row.icon = Icons.Icon({prayer.name, type='prayer'})
		row.type = [[Prayer]]
		local totalVal = 0
		for i, mod in ipairs(modifiers) do
			totalVal = totalVal + p.getModifierValue(prayer.modifiers, mod, skill, getOpposites)
		end
		row.val = totalVal

		row.modifierText, row.otherModifiers = getModText(prayer.modifiers)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local upgradeList = p.getUpgradesWithModifier(modifiers, skill, getOpposites)
	for i, upgrade in Shared.skpairs(upgradeList) do
		local row = {}
		row.name = upgrade.name
		row.icon = Icons.Icon({upgrade.name, type='upgrade'})
		row.type = '[[Shop|Upgrade]]'
		local totalVal = 0
		for i, mod in pairs(modifiers) do
			totalVal = totalVal + p.getModifierValue(upgrade.contains.modifiers, mod, skill, getOpposites)
		end
		row.val = totalVal

		row.modifierText, row.otherModifiers = getModText(upgrade.contains.modifiers)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local constellationList = p.getConstellationsWithModifier(modifiers, skill, getOpposites)
	for i, cons in ipairs(constellationList) do
		local row = {}
		row.name = cons.name
		row.icon = Icons.Icon({cons.name, type='constellation'})
		row.type = '[[Astrology#Constellations|Constellation]]'
		row.val = 15 -- Assume highest possible, the range is 1 to 15 inclusive

		local modList = Skills._buildAstrologyModifierArray(cons, {1, 15}, true, true, true, true)
		row.modifierText, row.otherModifiers = getModText(modList)

		if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
			hasOtherModifiers = true
		end

		table.insert(tableArray, row)
	end

	local result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Source!!Type!!'..columnName
	if hasOtherModifiers and displayOtherMods then result = result..'!!Other Modifiers' end

	--Sort by value if only one modifier was passed in
	--Otherwise sort alphabetically by type, then name
	table.sort(tableArray, function(a, b)
			if modifierCount == 1 and a.val ~= b.val then
				return a.val > b.val
			elseif a.type ~= b.type then
				return a.type < b.type
			else
				return a.name < b.name
			end
		end)
	for i, row in Shared.skpairs(tableArray) do
		result = result..'\r\n|-'
		result = result..'\r\n|data-sort-value="'..row.name..'"|'..row.icon
		result = result..'||'..row.type..'||data-sort-value="'..row.val..'"|'..row.modifierText
		if hasOtherModifiers and displayOtherMods then
			result = result..'||'..row.otherModifiers
		end
	end

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

function p.getModifierTable(frame)
	local modifier = frame.args ~= nil and frame.args[1] or frame[1]
	local skill = frame.args ~= nil and frame.args.skill or frame.skill
	local columnName = frame.args ~= nil and frame.args[2] or frame[2]
	local getOpposites = frame.args ~= nil and frame.args[3] or frame[3]
	local displayOtherMods = frame.args ~= nil and frame.args.displayOtherMods or frame.displayOtherMods
	local maxOtherMods = frame.args ~= nil and tonumber(frame.args.maxOtherMods) or 5

	if Shared.contains(modifier, ',') then
		modifier = Shared.splitString(modifier, ',')
	end

	if getOpposites ~= nil then
		getOpposites = string.upper(getOpposites) ~= 'FALSE'
	else
		getOpposites = true
	end

	if displayOtherMods ~= nil then
		displayOtherMods = string.upper(displayOtherMods) ~= 'FALSE'
	else
		displayOtherMods = true
	end

	return p._getModifierTable(modifier, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
end

return p