Module:ModifierTables: Difference between revisions

From Melvor Idle
(fixed a potential bug with getModifierTable if no maxOtherMods was sent in)
(_getModifierTable: Add Astrology constelllations; Indent with tabs instead of spaces)
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 GatheringSkills = require('Module:Skills/Gathering')
local Agility = require('Module:Skills/Agility')
local Agility = require('Module:Skills/Agility')
local Prayer = require('Module:Prayer')
local Prayer = require('Module:Prayer')
Line 15: Line 16:
--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
--Make sure we have the skillID and not the name
  if skill == '' then
if skill == '' then
    skill = nil
skill = nil
  elseif type(skill) == 'string' then
elseif type(skill) == 'string' then
    skill = Constants.getSkillID(skill)
skill = Constants.getSkillID(skill)
  end
end


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


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


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


  return increaseVal - decreaseVal
return increaseVal - decreaseVal
end
end


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


function p.getObstaclesWithModifier(modifiers, skill, getOpposites)
function p.getObstaclesWithModifier(modifiers, skill, getOpposites)
  if type(modifiers) == 'string' then
if type(modifiers) == 'string' then
    modifiers = {modifiers}
modifiers = {modifiers}
  end
end
  local obstList = Agility.getObstacles(
local obstList = Agility.getObstacles(
        function(obst)
function(obst)
          local result = false
for i, mod in Shared.skpairs(modifiers) do
          for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(obst.modifiers, mod, skill, getOpposites) ~= 0 then
            if p.getModifierValue(obst.modifiers, mod, skill, getOpposites) ~= 0 then
return true
              result = true
end
              break
end
            end
return false
          end
end)
          return result
return obstList
        end)
end
  return obstList
 
function p.getConstellationsWithModifier(modifiers, skill, getOpposites)
if type(modifiers) == 'string' then
modifiers = {modifiers}
end
local consList = GatheringSkills.getConstellations(
function(cons)
local consMods = GatheringSkills._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.getPillarsWithModifier(modifiers, skill, getOpposites)
function p.getPillarsWithModifier(modifiers, skill, getOpposites)
  if type(modifiers) == 'string' then
if type(modifiers) == 'string' then
    modifiers = {modifiers}
modifiers = {modifiers}
  end
end
  local pillarList = Agility.getPillars(
local pillarList = Agility.getPillars(
        function(pillar)
function(pillar)
          local result = false
for i, mod in Shared.skpairs(modifiers) do
          for i, mod in Shared.skpairs(modifiers) do
if p.getModifierValue(pillar.modifiers, mod, skill, getOpposites) ~= 0 then
            if p.getModifierValue(pillar.modifiers, mod, skill, getOpposites) ~= 0 then
return true
              result = true
end
              break
end
            end
return false
          end
end)
          return result
return pillarList
        end)
  return pillarList
end
end


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


Line 158: Line 168:


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


function p._getModifierTable(modifiers, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
function p._getModifierTable(modifiers, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
  local modifierNames = {}
local modifierNames = {}
  if type(modifiers) == 'string' then
if type(modifiers) == 'string' then
    modifiers = {modifiers}
modifiers = {modifiers}
  end
end
  for i, modifier in pairs(modifiers) do
for i, modifier in pairs(modifiers) do
    if getOpposites then
if getOpposites then
      table.insert(modifierNames, 'increased'..modifier)
table.insert(modifierNames, 'increased'..modifier)
      table.insert(modifierNames, 'decreased'..modifier)
table.insert(modifierNames, 'decreased'..modifier)
    else
else
      table.insert(modifierNames, modifier)
table.insert(modifierNames, modifier)
    end
end
  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 style="float:left;margin-left:0;margin-right:1em" 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 hasOtherModifiers = false
local petList = p.getPetsWithModifier(modifiers, skill, getOpposites)
  local modifierCount = Shared.tableCount(modifiers)
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


  if skill == '' then
row.modifierText, row.otherModifiers = getModText(pet.modifiers)
    skill = nil
  elseif type(skill) == 'string' then
    skill = Constants.getSkillID(skill)
  end


  local getModText =
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
    function(modifiers)
hasOtherModifiers = true
      local modTextArray = { ["visible"] = {}, ["overflow"] = {} }
end
      local otherModCount = 0
      local mainModText = {}
      for modName, modValue in Shared.skpairs(modifiers) do
        if Shared.contains(modifierNames, modName) then
          if type(modValue) == '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 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 style="float:left;margin-left:0;margin-right:1em" 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 = {}
table.insert(tableArray, row)
  --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
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)
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 string.len(row.otherModifiers) > 0 then
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
      hasOtherModifiers = true
hasOtherModifiers = true
    end
end


    table.insert(tableArray, row)
table.insert(tableArray, row)
  end
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)
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


    if string.len(row.otherModifiers) > 0 then
row.modifierText, row.otherModifiers = getModText(pillar.modifiers)
      hasOtherModifiers = true
    end


    table.insert(tableArray, row)
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
  end
hasOtherModifiers = true
  local obstList = p.getObstaclesWithModifier(modifiers, skill, getOpposites)
end
  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)
table.insert(tableArray, row)
end


    if string.len(row.otherModifiers) > 0 then
local prayerList = p.getPrayersWithModifier(modifiers, skill, getOpposites)
      hasOtherModifiers = true
for i, prayer in ipairs(prayerList) do
    end
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


    table.insert(tableArray, row)
row.modifierText, row.otherModifiers = getModText(prayer.modifiers)
  end


  local pillarList = p.getPillarsWithModifier(modifiers, skill, getOpposites)
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
  for i, pillar in Shared.skpairs(pillarList) do
hasOtherModifiers = true
    local row = {}
end
    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)
table.insert(tableArray, row)
end


    if string.len(row.otherModifiers) > 0 then
local upgradeList = p.getUpgradesWithModifier(modifiers, skill, getOpposites)
      hasOtherModifiers = true
for i, upgrade in Shared.skpairs(upgradeList) do
    end
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


    table.insert(tableArray, row)
row.modifierText, row.otherModifiers = getModText(upgrade.contains.modifiers)
  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 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


    if string.len(row.otherModifiers) > 0 then
table.insert(tableArray, row)
      hasOtherModifiers = true
end
    end


    table.insert(tableArray, row)
local constellationList = p.getConstellationsWithModifier(modifiers, skill, getOpposites)
  end
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 result = '{| class="wikitable sortable stickyHeader"'
local modList = GatheringSkills._buildAstrologyModifierArray(cons, {1, 15}, true, true, true, true)
  result = result..'\r\n|- class="headerRow-0"'
row.modifierText, row.otherModifiers = getModText(modList)
  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
if not hasOtherModifiers and string.len(row.otherModifiers) > 0 then
  --Otherwise sort alphabetically by type, then name
hasOtherModifiers = true
  table.sort(tableArray, function(a, b)
end
                          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|}'
table.insert(tableArray, row)
  return result
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
end


function p.getModifierTable(frame)
function p.getModifierTable(frame)
  local modifier = frame.args ~= nil and frame.args[1] or frame[1]
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 skill = frame.args ~= nil and frame.args.skill or frame.skill
  local columnName = frame.args ~= nil and frame.args[2] or frame[2]
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 getOpposites = frame.args ~= nil and frame.args[3] or frame[3]
  local displayOtherMods = frame.args ~= nil and frame.args.displayOtherMods or frame.displayOtherMods
local displayOtherMods = frame.args ~= nil and frame.args.displayOtherMods or frame.displayOtherMods
  local maxOtherMods = frame.args ~= nil and tonumber(frame.args.maxOtherMods) or 5
local maxOtherMods = frame.args ~= nil and tonumber(frame.args.maxOtherMods) or 5


  if Shared.contains(modifier, ',') then
if Shared.contains(modifier, ',') then
    modifier = Shared.splitString(modifier, ',')
modifier = Shared.splitString(modifier, ',')
  end
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


  if getOpposites ~= nil then
return p._getModifierTable(modifier, skill, columnName, getOpposites, displayOtherMods, maxOtherMods)
    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 03:07, 25 January 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 GatheringSkills = require('Module:Skills/Gathering')
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)
			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 = GatheringSkills.getConstellations(
			function(cons)
				local consMods = GatheringSkills._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)
			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 style="float:left;margin-left:0;margin-right:1em" 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 = GatheringSkills._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