Module:ModifierTables: Difference between revisions
From Melvor Idle
Falterfire (talk | contribs) (More bugfixes) |
(Add Mastery Pool Bonuses to Modifier Tables) |
||
(79 intermediate revisions by 6 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 | --This includes Agility, Equipment, Pets, Prayers, and Constellations right now | ||
local p = {} | local p = {} | ||
Line 6: | Line 6: | ||
local Constants = require('Module:Constants') | local Constants = require('Module:Constants') | ||
local Shared = require('Module:Shared') | local Shared = require('Module:Shared') | ||
local Common = require('Module:Common') | |||
local Num = require('Module:Number') | |||
local Icons = require('Module:Icons') | |||
local GameData = require('Module:GameData') | |||
local SkillData = GameData.skillData | |||
local Modifiers = require('Module:Modifiers') | |||
local SkillTree = require('Module:SkillTree') | |||
local Items = require('Module:Items') | |||
local Shop = require('Module:Shop') | |||
local Pets = require('Module:Pets') | local Pets = require('Module:Pets') | ||
local | local Skills = require('Module:Skills') | ||
local Agility = require('Module:Skills/Agility') | local Agility = require('Module:Skills/Agility') | ||
local | local Cartography = require('Module:Skills/Cartography') | ||
local | local Prayer = require('Module:Prayer') | ||
local Summoning = require('Module:Skills/Summoning') | |||
local Township = require('Module:Township') | |||
--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. | function p.getItemsWithModifier(modifierCriteria) | ||
local itemList = Items.getItems( | |||
function(item) | |||
if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then | |||
return false | |||
elseif item.modifiers == nil or Shared.tableIsEmpty(item.modifiers) then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(item.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return itemList | |||
end | |||
function p.getSkillTreeNodesWithModifier(modifierCriteria) | |||
local nodesWithModifier = SkillTree.getSkillTreeNodes( | |||
function(node) | |||
if node.modifiers ~= nil then | |||
local mods = Modifiers.getMatchingModifiers(node.modifiers, modifierCriteria) | |||
if not Shared.tableIsEmpty(mods.matched) then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
) | |||
return nodesWithModifier | |||
end | |||
function p.getObstaclesWithModifier(modifierCriteria) | |||
local obstList = Agility.getObstacles( | |||
function(obst) | |||
if obst.modifiers ~= nil then | |||
local mods = Modifiers.getMatchingModifiers(obst.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end | |||
return false | |||
end) | |||
return obstList | |||
end | |||
function p.getConstellationsWithModifier(modifierCriteria) | |||
local consList = Skills.getConstellations( | |||
function(cons) | |||
local consMods = Skills._getConstellationModifiers(cons) | |||
for modType, modsForType in pairs(consMods) do | |||
local modData = {} | |||
-- Compile player modifiers | |||
for _, mods in ipairs(modsForType) do | |||
if mods.modifiers ~= nil then | |||
for modKey, modDefn in pairs(mods.modifiers) do | |||
if type(modData[modKey]) == 'table' and modData[modKey][1] ~= nil then | |||
for _, v in ipairs(modDefn) do | |||
table.insert(modData[modKey], v) | |||
end | |||
else | |||
modData[modKey] = modDefn | |||
end | |||
end | |||
end | |||
end | |||
local mods = Modifiers.getMatchingModifiers(modData, modifierCriteria) | |||
if not Shared.tableIsEmpty(mods.matched) then | |||
return true | |||
end | |||
end | |||
return false | |||
end) | |||
return consList | |||
end | |||
function p.getPillarsWithModifier(modifierCriteria) | |||
local pillarList = Agility.getPillars( | |||
function(pillar) | |||
if pillar.modifiers ~= nil then | |||
local mods = Modifiers.getMatchingModifiers(pillar.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end | |||
return false | |||
end) | |||
return pillarList | |||
end | |||
function p.getPetsWithModifier(modifierCriteria) | |||
local petList = Pets.getPets( | |||
function(pet) | |||
if pet.modifiers ~= nil then | |||
local mods = Modifiers.getMatchingModifiers(pet.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end | |||
return false | |||
end) | |||
return petList | |||
end | |||
function p.getPrayersWithModifier(modifierCriteria) | |||
local prayerList = Prayer.getPrayers( | |||
function(prayer) | |||
if prayer.modifiers ~= nil then | |||
local mods = Modifiers.getMatchingModifiers(prayer.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end | |||
return false | |||
end) | |||
return prayerList | |||
end | |||
function p.getUpgradesWithModifier(modifierCriteria) | |||
local upgradeList = Shop.getPurchases( | |||
function(purchase) | |||
if purchase.category == 'melvorD:GolbinRaid' | |||
or purchase.contains == nil | |||
or purchase.contains.modifiers == nil | |||
or Shared.tableIsEmpty(purchase.contains.modifiers) then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(purchase.contains.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return upgradeList | |||
end | |||
function p.getPOIsWithModifier(modifierCriteria) | |||
local POIList = Cartography.getPointsOfInterest( | |||
function(POI) | |||
if POI.activeStats == nil or POI.activeStats.modifiers == nil then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(POI.activeStats.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return POIList | |||
end | |||
function p.getCartoMasteryBonusesWithModifier(modifierCriteria) | |||
local bonusList = Cartography.getMasteryBonuses( | |||
function(bonus) | |||
if bonus.modifiers == nil or Shared.tableIsEmpty(bonus.modifiers) then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(bonus.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return bonusList | |||
end | |||
function p.getAncientRelicsWithModifiers(modifierCriteria) | |||
local matchedRelics = {} | |||
for i, relic in ipairs(GameData.rawData.ancientRelics) do | |||
if relic.modifiers ~= nil then | |||
local mods = Modifiers.getMatchingModifiers(relic.modifiers, modifierCriteria) | |||
if not Shared.tableIsEmpty(mods.matched) then | |||
table.insert(matchedRelics, relic) | |||
end | |||
end | |||
end | |||
return matchedRelics | |||
end | end | ||
function p. | function p.getBuildingsWithModifiers(modifierCriteria) | ||
local buildingList = Township.getBuildings( | |||
function(building) | |||
if building.modifiers == nil or Shared.tableIsEmpty(building.modifiers) then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(building.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return buildingList | |||
end | end | ||
function p. | function p.getSeasonsWithModifiers(modifierCriteria) | ||
local seasonList = Township.getSeasons( | |||
function(season) | |||
if season.modifiers == nil or Shared.tableIsEmpty(season.modifiers) then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(season.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return seasonList | |||
end | end | ||
function p. | function p.getSummoningSynergiesWithModifiers(modifierCriteria) | ||
local synergyList = Summoning.getSynergies( | |||
function(synergy) | |||
if synergy.modifiers == nil or Shared.tableIsEmpty(synergy.modifiers) then | |||
return false | |||
end | |||
local mods = Modifiers.getMatchingModifiers(synergy.modifiers, modifierCriteria) | |||
return not Shared.tableIsEmpty(mods.matched) | |||
end) | |||
return synergyList | |||
end | end | ||
function p. | function p.getMasteryPoolModifiers(modifierCriteria) | ||
local masteryPoolList = {} | |||
for skillName, skillData in pairs(SkillData) do | |||
if skillData.masteryPoolBonuses ~= nil then | |||
for i, masteryPool in ipairs(skillData.masteryPoolBonuses) do | |||
local mods = Modifiers.getMatchingModifiers(masteryPool.modifiers, modifierCriteria) | |||
if not Shared.tableIsEmpty(mods.matched) then | |||
table.insert(masteryPoolList, { [skillName] = masteryPool }) | |||
end | |||
end | |||
end | |||
end | |||
return masteryPoolList | |||
end | end | ||
function p._getModifierTable(modifiers, | function p._getModifierTable(modifiers, globalProps, columnName, getOpposites, displayOtherMods, maxOtherMods, forceMagnitudeSort, collapsed) | ||
local modifierIDs = {} | |||
if type(modifiers) == 'string' then | |||
modifiers = {modifiers} | |||
end | |||
for i, modifier in ipairs(modifiers) do | |||
-- Ensure only the local ID is used in case the provided modifier ID is namespaced | |||
local modNS, modID = Shared.getLocalID(modifier.id) | |||
-- Convert modifier & global property names to IDs | |||
local globalPropIDs = Modifiers.convertCriteriaNamesToIDs(globalProps or {}) | |||
local modPropIDs = Modifiers.convertCriteriaNamesToIDs(modifier.props or {}) | |||
-- Combine properties, mod props must be last as the highest priority | |||
local combinedProps = Modifiers.combineDataCriteria({ globalPropIDs, modPropIDs }) | |||
if Modifiers.getModifierByID(modID) ~= nil then | |||
-- Provided ID is a modifier ID (as opposed to an alias) | |||
table.insert(modifierIDs, { | |||
["id"] = modID, | |||
["type"] = 'id', | |||
["props"] = combinedProps | |||
}) | |||
else | |||
-- Assume modID is a modifier alias | |||
if getOpposites then | |||
local incModAlias, decModAlias = 'increased' .. modID, 'decreased' .. modID | |||
local incMod, decMod = Modifiers.getModifierByAlias(incModAlias), Modifiers.getModifierByAlias(decModAlias) | |||
-- If neither alias resolves to a modifier, then let user know this is invalid | |||
if incMod == nil and decMod == nil then | |||
error('No such modifier alias: ' .. modID, 2) | |||
end | |||
-- Don't include increased or decreased variants if they don't resolve to a modifier, | |||
-- as doing so will generate an error about an invalid alias later | |||
if incMod ~= nil then | |||
table.insert(modifierIDs, { | |||
["id"] = incModAlias, | |||
["type"] = 'alias', | |||
["props"] = combinedProps | |||
}) | |||
end | |||
if decMod ~= nil then | |||
table.insert(modifierIDs, { | |||
["id"] = decModAlias, | |||
["type"] = 'alias', | |||
["props"] = combinedProps | |||
}) | |||
end | |||
else | |||
table.insert(modifierIDs, { | |||
["id"] = modID, | |||
["type"] = 'alias', | |||
["props"] = combinedProps | |||
}) | |||
end | |||
end | |||
end | |||
local modifierCriteria = Modifiers.getMatchCriteriaFromIDs(modifierIDs) | |||
local hasOtherModifiers = false | |||
local modifierCount = Shared.tableCount(modifiers) | |||
local getModText = | |||
function(modifiers) | |||
local matchedMods = Modifiers.getMatchingModifiers(modifiers, modifierCriteria) | |||
local mainModText = Modifiers.getModifiersText(matchedMods.matched, true, false, maxOtherMods) | |||
local otherModText = Modifiers.getModifiersText(matchedMods.unmatched, true, false, maxOtherMods) | |||
return mainModText, otherModText, matchedMods | |||
end | |||
local tableArray = {} | |||
--Going through each type of thing to add to the array | |||
local itemList = p.getItemsWithModifier(modifierCriteria) | |||
for i, item in ipairs(itemList) do | |||
local row = {} | |||
row.name = item.name | |||
row.icon = Icons.Icon({item.name, type='item'}) | |||
row.expIcon = Icons.getDLCColumnIcon(item.id) | |||
row.expSort = Icons.getExpansionID(item.id) | |||
row.type = 'Item' | |||
row.typeText = row.type | |||
--For equipment, show the slot they go in | |||
if item.validSlots ~= nil and not Shared.tableIsEmpty(item.validSlots) then | |||
local rowTypePart = {} | |||
for j, slot in ipairs(item.validSlots) do | |||
table.insert(rowTypePart, Common.getEquipmentSlotLink(slot)) | |||
end | |||
row.typeText = row.typeText .. ' (' .. table.concat(item.validSlots, ', ') .. ')' | |||
row.type = row.type .. ' (' .. table.concat(rowTypePart, ', ') .. ')' | |||
end | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(item.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local petList = p.getPetsWithModifier(modifierCriteria) | |||
for i, pet in Shared.skpairs(petList) do | |||
local row = {} | |||
row.name = pet.name | |||
row.icon = Icons.Icon({pet.name, type='pet'}) | |||
row.expIcon = Icons.getDLCColumnIcon(pet.id) | |||
row.expSort = Icons.getExpansionID(pet.id) | |||
row.type = '[[Pets|Pet]]' | |||
row.typeText = 'Pet' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(pet.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local nodeList = p.getSkillTreeNodesWithModifier(modifierCriteria) | |||
for _, node in ipairs(nodeList) do | |||
local row = {} | |||
row.name = node.skillName .. " - " .. node.name | |||
local firstIcon = Icons.Icon({"", img='Skill Tree', nolink=true}) | |||
local secondIcon = Icons.Icon({node.skillName..'%23#Skill_Tree', node.name, type='skill', img=node.skillName}) | |||
row.icon = firstIcon .. " " .. secondIcon | |||
row.expIcon = Icons.getDLCColumnIcon(node.id) | |||
row.expSort = Icons.getExpansionID(node.id) | |||
row.type = '[[Skill Tree#Nodes|Skill Tree Node]]' | |||
row.typeText = 'Skill Tree Node' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(node.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local obstList = p.getObstaclesWithModifier(modifierCriteria) | |||
table.sort(obstList, function(a, b) return a.category < b.category end) | |||
for i, obst in Shared.skpairs(obstList) do | |||
local row = {} | |||
row.name = obst.name | |||
row.icon = Icons.Icon({'Agility%23'..string.gsub(obst.name, ' ', ''), obst.name, type='skill', img='Agility'}) | |||
row.expIcon = Icons.getDLCColumnIcon(obst.id) | |||
row.expSort = Icons.getExpansionID(obst.id) | |||
row.type = '[[Agility#Obstacles|Agility Obstacle '..tostring(tonumber(obst.category)+1)..']]' | |||
row.typeText = 'Agility Obstacle '..string.format("%02d", (obst.category + 1)) | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(obst.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local pillarList = p.getPillarsWithModifier(modifierCriteria) | |||
for i, pillar in ipairs(pillarList) do | |||
local row = {} | |||
row.name = pillar.name | |||
row.icon = Icons.Icon({'Agility%23'..string.gsub(pillar.name, ' ', ''), pillar.name, type='skill', img='Agility'}) | |||
row.expIcon = Icons.getDLCColumnIcon(pillar.id) | |||
row.expSort = Icons.getExpansionID(pillar.id) | |||
row.type = '[[Agility#Passive Pillars|Agility Pillar]]' | |||
row.typeText = 'Agility Pillar' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(pillar.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local prayerList = p.getPrayersWithModifier(modifierCriteria) | |||
for i, prayer in ipairs(prayerList) do | |||
local row = {} | |||
row.name = prayer.name | |||
row.icon = Icons.Icon({prayer.name, type='prayer'}) | |||
row.expIcon = Icons.getDLCColumnIcon(prayer.id) | |||
row.expSort = Icons.getExpansionID(prayer.id) | |||
row.type = [[Prayer]] | |||
row.typeText = 'Prayer' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(prayer.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local upgradeList = p.getUpgradesWithModifier(modifierCriteria) | |||
for i, upgrade in ipairs(upgradeList) do | |||
local row = {} | |||
row.name = Shop._getPurchaseName(upgrade) | |||
row.icon = Icons.Icon({row.name, type='upgrade'}) | |||
row.expIcon = Icons.getDLCColumnIcon(upgrade.id) | |||
row.expSort = Icons.getExpansionID(upgrade.id) | |||
row.type = '[[Shop|Upgrade]]' | |||
row.typeText = 'Upgrade' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(upgrade.contains.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local constellationList = p.getConstellationsWithModifier(modifierCriteria) | |||
for i, cons in ipairs(constellationList) do | |||
local modListByType = Skills._getConstellationModifiers(cons) | |||
local modList = {} | |||
-- Combine all mods into single list | |||
for modType, modsForType in pairs(modListByType) do | |||
for _, mod in ipairs(modsForType) do | |||
if mod.modifiers ~= nil then | |||
for modKey, modDefn in pairs(mod.modifiers) do | |||
if type(modList[modKey]) == 'table' and modList[modKey][1] ~= nil then | |||
for _, v in ipairs(modDefn) do | |||
table.insert(modList[modKey], v) | |||
end | |||
else | |||
modList[modKey] = modDefn | |||
end | |||
end | |||
end | |||
end | |||
end | |||
local row = {} | |||
row.name = cons.name | |||
row.icon = Icons.Icon({cons.name, type='constellation'}) | |||
row.expIcon = Icons.getDLCColumnIcon(cons.id) | |||
row.expSort = Icons.getExpansionID(cons.id) | |||
row.type = '[[Astrology#Constellations|Constellation]]' | |||
row.typeText = 'Constellation' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(modList) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local POIList = p.getPOIsWithModifier(modifierCriteria) | |||
for i, POI in ipairs(POIList) do | |||
local row = {} | |||
row.name = POI.name | |||
row.icon = Icons.Icon({POI.name, type='poi'}) | |||
row.expIcon = Icons.getDLCColumnIcon(POI.id) | |||
row.expSort = Icons.getExpansionID(POI.id) | |||
row.type = '[[Cartography|Point of Interest]]' | |||
row.typeText = 'Point of Interest' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(POI.activeStats.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local cartoBonusList = p.getCartoMasteryBonusesWithModifier(modifierCriteria) | |||
for i, bonus in ipairs(cartoBonusList) do | |||
local row = {} | |||
row.name = Num.formatnum(bonus.masteredHexes) .. ' Hexes Mastered' | |||
row.icon = Icons.Icon({'Cartography', Num.formatnum(bonus.masteredHexes) .. ' Hexes Mastered', type='skill'}) | |||
row.expIcon = Icons.getDLCColumnIcon(bonus.id) | |||
row.expSort = Icons.getExpansionID(bonus.id) | |||
row.type = Icons.Icon({'Cartography', 'Mastery Bonus', section='Mastery Unlocks', type='skill', noicon=true}) | |||
row.typeText = 'Mastery Bonus' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(bonus.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local ancientRelicList = p.getAncientRelicsWithModifiers(modifierCriteria) | |||
for i, relic in ipairs(ancientRelicList) do | |||
local row = {} | |||
local relicName = relic.name | |||
local sectionName = 'Melvor Realm' | |||
if string.find(relic.id, 'Abyssal') ~= nil then | |||
relicName = 'Abyssal ' .. relicName | |||
sectionName = 'Abyssal Realm' | |||
end | |||
row.name = relicName | |||
row.icon = Icons.Icon({'Ancient Relics', relicName, section=sectionName}) | |||
row.expIcon = Icons.getDLCColumnIcon(relic.id) | |||
row.expSort = Icons.getExpansionID(relic.id) | |||
row.type = Icons.Icon({'Ancient Relics', 'Ancient Relic', noicon=true}) | |||
row.typeText = 'Ancient Relic' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(relic.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local buildingList = p.getBuildingsWithModifiers(modifierCriteria) | |||
for i, building in ipairs(buildingList) do | |||
local row = {} | |||
row.name = building.name | |||
row.icon = Icons.Icon({building.name, type='building'}) | |||
row.expIcon = Icons.getDLCColumnIcon(building.id) | |||
row.expSort = Icons.getExpansionID(building.id) | |||
row.type = Icons.Icon({'Township', 'Building', section='Buildings', type='skill', noicon=true}) | |||
row.typeText = 'Building' | |||
local modList = {} | |||
-- Multiply mod value by max upgrades to get the total modifier value | |||
for modID, value in pairs(building.modifiers) do | |||
if type(value) == 'table' then | |||
modList[modID] = value[1].value * building.maxUpgrades | |||
else | |||
modList[modID] = value * building.maxUpgrades | |||
end | |||
end | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(modList) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local seasonList = p.getSeasonsWithModifiers(modifierCriteria) | |||
for i, season in ipairs(seasonList) do | |||
local row = {} | |||
row.name = season.name | |||
row.icon = Icons.Icon({season.name, type='township'}) | |||
row.expIcon = Icons.getDLCColumnIcon(season.id) | |||
row.expSort = Icons.getExpansionID(season.id) | |||
row.type = Icons.Icon({'Township', 'Season', section='Seasons', type='skill', noicon=true}) | |||
row.typeText = 'Season' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(season.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local summoningSynergyList = p.getSummoningSynergiesWithModifiers(modifierCriteria) | |||
for i, synergy in ipairs(summoningSynergyList) do | |||
local row = {} | |||
local famProduct1 = Summoning.getFamiliarRecipeByID(synergy.summonIDs[1]) | |||
local familiar1 = nil | |||
local famProduct2 = Summoning.getFamiliarRecipeByID(synergy.summonIDs[2]) | |||
local familiar2 = nil | |||
if famProduct1 ~= nil then | |||
familiar1 = Items.getItemByID(famProduct1.productID) | |||
end | |||
if famProduct2 ~= nil then | |||
familiar2 = Items.getItemByID(famProduct2.productID) | |||
end | |||
if familiar1 == nil or familiar2 == nil then | |||
return | |||
end | |||
row.name = familiar1.name .. familiar2.name .. ' Synergy' | |||
row.icon = Icons.Icon({familiar1.name, type='item'}) .. ' ' .. Icons.Icon({'SynergyIcon', notext=true, nolink=true}) .. ' ' .. Icons.Icon({familiar2.name, type='item'}) .. ' Synergy' | |||
row.expIcon = Icons.getDLCColumnIcon(familiar2.id) | |||
row.expSort = Icons.getExpansionID(familiar2.id) | |||
row.type = Icons.Icon({'Summoning', 'Summoning Synergy', section='Synergies', type='skill', noicon=true}) | |||
row.typeText = 'Synergy' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(synergy.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
local masteryPools = p.getMasteryPoolModifiers(modifierCriteria) | |||
for i, masteryPoolData in ipairs(masteryPools) do | |||
for skillName, masteryPool in pairs(masteryPoolData) do | |||
local row = {} | |||
local isAbyssal = masteryPool.realm == 'melvorItA:Abyssal' and 'Abyssal ' or '' | |||
row.name = isAbyssal .. masteryPool.percent .. '% Mastery Pool Bonus' | |||
row.icon = Icons.Icon({skillName, row.name, section='Mastery Pool Checkpoints', type='skill'}) | |||
row.expIcon = Icons.getDLCColumnIcon(masteryPool.realm) | |||
row.expSort = Icons.getExpansionID(masteryPool.realm) | |||
row.type = Icons.Icon({skillName, 'Mastery Pool Bonus', section='Mastery Pool Checkpoints', type='skill', noicon=true}) | |||
row.typeText = 'Mastery Pool Bonus' | |||
local objMods = nil | |||
row.modifierText, row.otherModifiers, objMods = getModText(masteryPool.modifiers) | |||
row.val = Modifiers.getModifierValue(objMods.matched) | |||
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then | |||
hasOtherModifiers = true | |||
end | |||
table.insert(tableArray, row) | |||
end | |||
end | |||
local html = mw.html.create('table') | |||
:addClass("wikitable sortable stickyHeader mw-collapsible") | |||
if collapsed == true then | |||
html:addClass("mw-collapsed") | |||
end | |||
local header = html:tag('tr'):addClass("headerRow-0") | |||
header:tag('th'):wikitext('Source') | |||
:tag('th'):wikitext('Type') | |||
:tag('th'):wikitext('[[DLC]]') | |||
:tag('th'):wikitext(columnName) | |||
if hasOtherModifiers and displayOtherMods then | |||
header:tag('th'):wikitext('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 or forceMagnitudeSort) and a.val ~= b.val then | |||
return a.val > b.val | |||
elseif a.typeText ~= b.typeText then | |||
return a.typeText < b.typeText | |||
else | |||
return a.name < b.name | |||
end | |||
end) | |||
for i, row in ipairs(tableArray) do | |||
local datarow = html:tag('tr') | |||
datarow:tag('td'):wikitext(row.icon) | |||
:attr('data-sort-value', row.name) | |||
datarow:tag('td'):wikitext(row.type) | |||
:attr('data-sort-value', row.typeText) | |||
datarow:tag('td'):wikitext(row.expIcon) | |||
:css('text-align', 'center') | |||
:attr('data-sort-value', row.expSort) | |||
datarow:tag('td'):wikitext(row.modifierText) | |||
:attr('data-sort-value', row.val) | |||
if hasOtherModifiers and displayOtherMods then | |||
datarow:tag('td'):wikitext(row.otherModifiers) | |||
end | |||
end | |||
return tostring(html) | |||
end | end | ||
function p.getModifierTable(frame) | function p.getModifierTable(frame) | ||
local args = frame.args ~= nil and frame.args or frame | |||
local modifier = args[1] | |||
local columnName = args[2] | |||
local getOpposites = args[3] | |||
local displayOtherMods = args.displayOtherMods | |||
local maxOtherMods = tonumber(args.maxOtherMods) or 5 | |||
local forceMagnitudeSort = string.upper(tostring(args.forceMagnitudeSort)) == 'TRUE' or false | |||
local globalPropsText = args.filters | |||
local collapsed = string.upper(tostring(args.collapsed)) == 'TRUE' or false | |||
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 | |||
-- Given a text string following format 'key1=val1;key2=val2;...', returns | |||
-- a table: { key1 = val1, key2 = val2, ... } | |||
local function modPropTextToTable(propText) | |||
local propTable = {} | |||
local propParts = Shared.splitString(propText, ';') | |||
for _, propPart in ipairs(propParts) do | |||
local valueStartIdx, _ = string.find(propPart, ':') | |||
if valueStartIdx ~= nil then | |||
local k = string.sub(propPart, 1, valueStartIdx - 1) | |||
local v = string.sub(propPart, valueStartIdx + 1, -1) | |||
propTable[k] = v | |||
end | |||
end | |||
return propTable | |||
end | |||
local globalProps = {} | |||
if globalPropsText ~= nil then | |||
globalProps = modPropTextToTable(globalPropsText) | |||
end | |||
local modifierList = {} | |||
local modifierListCrude = Shared.splitString(modifier, ',') | |||
-- At this point, modifierListCrude requires further processing to separate modifier IDs | |||
-- and properties | |||
for _, modEntry in ipairs(modifierListCrude) do | |||
local modID, modProps = nil, {} | |||
local propStartIdx, _ = string.find(modEntry, '[[]') -- Matches plain text '[' | |||
if propStartIdx == nil then | |||
-- No properties specified, the entire string is a modifier ID | |||
modID = modEntry | |||
else | |||
modID = string.sub(modEntry, 1, propStartIdx - 1) | |||
local modPropText = string.sub(modEntry, propStartIdx + 1, -2) | |||
modProps = modPropTextToTable(modPropText) | |||
end | |||
table.insert(modifierList, { | |||
["id"] = modID, | |||
["props"] = modProps | |||
}) | |||
end | |||
return p._getModifierTable(modifierList, globalProps, columnName, getOpposites, displayOtherMods, maxOtherMods, forceMagnitudeSort, collapsed) | |||
end | |||
-- Function to list all available modifiers for the relevant templates. | |||
function p.getAllModifiers() | |||
local tabl = mw.html.create('table') | |||
:addClass('mw-collapsible mw-collapsed') | |||
tabl:tag('caption') | |||
:css('min-width', '200px') | |||
:tag('b') | |||
:wikitext('All Modifiers List') | |||
-- First, sort modifiers | |||
local modifierNames = {} | |||
for k, _ in pairs(Modifiers.ModifierIndex.localID) do | |||
table.insert(modifierNames, k) | |||
end | |||
table.sort(modifierNames) | |||
-- Then add modifiers to output table | |||
for _, v in pairs(modifierNames) do | |||
tabl:tag('tr') | |||
:tag('td') | |||
:tag('code') | |||
:wikitext(tostring(v)):done() | |||
:done() | |||
:done() | |||
end | |||
return tostring(tabl) | |||
end | |||
--Function for console testing of modifier tables | |||
function p.getModifierTableTest() | |||
return p.getModifierTable({args = {'id:flatBaseRandomProductQuantity[item=Abyssal Stardust]', 'GP Boosts', filters = 'skill=Astrology'}}) | |||
end | end | ||
return p | return p |
Latest revision as of 23:08, 15 October 2024
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 Common = require('Module:Common')
local Num = require('Module:Number')
local Icons = require('Module:Icons')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Modifiers = require('Module:Modifiers')
local SkillTree = require('Module:SkillTree')
local Items = require('Module:Items')
local Shop = require('Module:Shop')
local Pets = require('Module:Pets')
local Skills = require('Module:Skills')
local Agility = require('Module:Skills/Agility')
local Cartography = require('Module:Skills/Cartography')
local Prayer = require('Module:Prayer')
local Summoning = require('Module:Skills/Summoning')
local Township = require('Module:Township')
--First up, functions to get all the things in a category that have a given modifier:
function p.getItemsWithModifier(modifierCriteria)
local itemList = Items.getItems(
function(item)
if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then
return false
elseif item.modifiers == nil or Shared.tableIsEmpty(item.modifiers) then
return false
end
local mods = Modifiers.getMatchingModifiers(item.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return itemList
end
function p.getSkillTreeNodesWithModifier(modifierCriteria)
local nodesWithModifier = SkillTree.getSkillTreeNodes(
function(node)
if node.modifiers ~= nil then
local mods = Modifiers.getMatchingModifiers(node.modifiers, modifierCriteria)
if not Shared.tableIsEmpty(mods.matched) then
return true
end
end
return false
end
)
return nodesWithModifier
end
function p.getObstaclesWithModifier(modifierCriteria)
local obstList = Agility.getObstacles(
function(obst)
if obst.modifiers ~= nil then
local mods = Modifiers.getMatchingModifiers(obst.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end
return false
end)
return obstList
end
function p.getConstellationsWithModifier(modifierCriteria)
local consList = Skills.getConstellations(
function(cons)
local consMods = Skills._getConstellationModifiers(cons)
for modType, modsForType in pairs(consMods) do
local modData = {}
-- Compile player modifiers
for _, mods in ipairs(modsForType) do
if mods.modifiers ~= nil then
for modKey, modDefn in pairs(mods.modifiers) do
if type(modData[modKey]) == 'table' and modData[modKey][1] ~= nil then
for _, v in ipairs(modDefn) do
table.insert(modData[modKey], v)
end
else
modData[modKey] = modDefn
end
end
end
end
local mods = Modifiers.getMatchingModifiers(modData, modifierCriteria)
if not Shared.tableIsEmpty(mods.matched) then
return true
end
end
return false
end)
return consList
end
function p.getPillarsWithModifier(modifierCriteria)
local pillarList = Agility.getPillars(
function(pillar)
if pillar.modifiers ~= nil then
local mods = Modifiers.getMatchingModifiers(pillar.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end
return false
end)
return pillarList
end
function p.getPetsWithModifier(modifierCriteria)
local petList = Pets.getPets(
function(pet)
if pet.modifiers ~= nil then
local mods = Modifiers.getMatchingModifiers(pet.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end
return false
end)
return petList
end
function p.getPrayersWithModifier(modifierCriteria)
local prayerList = Prayer.getPrayers(
function(prayer)
if prayer.modifiers ~= nil then
local mods = Modifiers.getMatchingModifiers(prayer.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end
return false
end)
return prayerList
end
function p.getUpgradesWithModifier(modifierCriteria)
local upgradeList = Shop.getPurchases(
function(purchase)
if purchase.category == 'melvorD:GolbinRaid'
or purchase.contains == nil
or purchase.contains.modifiers == nil
or Shared.tableIsEmpty(purchase.contains.modifiers) then
return false
end
local mods = Modifiers.getMatchingModifiers(purchase.contains.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return upgradeList
end
function p.getPOIsWithModifier(modifierCriteria)
local POIList = Cartography.getPointsOfInterest(
function(POI)
if POI.activeStats == nil or POI.activeStats.modifiers == nil then
return false
end
local mods = Modifiers.getMatchingModifiers(POI.activeStats.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return POIList
end
function p.getCartoMasteryBonusesWithModifier(modifierCriteria)
local bonusList = Cartography.getMasteryBonuses(
function(bonus)
if bonus.modifiers == nil or Shared.tableIsEmpty(bonus.modifiers) then
return false
end
local mods = Modifiers.getMatchingModifiers(bonus.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return bonusList
end
function p.getAncientRelicsWithModifiers(modifierCriteria)
local matchedRelics = {}
for i, relic in ipairs(GameData.rawData.ancientRelics) do
if relic.modifiers ~= nil then
local mods = Modifiers.getMatchingModifiers(relic.modifiers, modifierCriteria)
if not Shared.tableIsEmpty(mods.matched) then
table.insert(matchedRelics, relic)
end
end
end
return matchedRelics
end
function p.getBuildingsWithModifiers(modifierCriteria)
local buildingList = Township.getBuildings(
function(building)
if building.modifiers == nil or Shared.tableIsEmpty(building.modifiers) then
return false
end
local mods = Modifiers.getMatchingModifiers(building.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return buildingList
end
function p.getSeasonsWithModifiers(modifierCriteria)
local seasonList = Township.getSeasons(
function(season)
if season.modifiers == nil or Shared.tableIsEmpty(season.modifiers) then
return false
end
local mods = Modifiers.getMatchingModifiers(season.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return seasonList
end
function p.getSummoningSynergiesWithModifiers(modifierCriteria)
local synergyList = Summoning.getSynergies(
function(synergy)
if synergy.modifiers == nil or Shared.tableIsEmpty(synergy.modifiers) then
return false
end
local mods = Modifiers.getMatchingModifiers(synergy.modifiers, modifierCriteria)
return not Shared.tableIsEmpty(mods.matched)
end)
return synergyList
end
function p.getMasteryPoolModifiers(modifierCriteria)
local masteryPoolList = {}
for skillName, skillData in pairs(SkillData) do
if skillData.masteryPoolBonuses ~= nil then
for i, masteryPool in ipairs(skillData.masteryPoolBonuses) do
local mods = Modifiers.getMatchingModifiers(masteryPool.modifiers, modifierCriteria)
if not Shared.tableIsEmpty(mods.matched) then
table.insert(masteryPoolList, { [skillName] = masteryPool })
end
end
end
end
return masteryPoolList
end
function p._getModifierTable(modifiers, globalProps, columnName, getOpposites, displayOtherMods, maxOtherMods, forceMagnitudeSort, collapsed)
local modifierIDs = {}
if type(modifiers) == 'string' then
modifiers = {modifiers}
end
for i, modifier in ipairs(modifiers) do
-- Ensure only the local ID is used in case the provided modifier ID is namespaced
local modNS, modID = Shared.getLocalID(modifier.id)
-- Convert modifier & global property names to IDs
local globalPropIDs = Modifiers.convertCriteriaNamesToIDs(globalProps or {})
local modPropIDs = Modifiers.convertCriteriaNamesToIDs(modifier.props or {})
-- Combine properties, mod props must be last as the highest priority
local combinedProps = Modifiers.combineDataCriteria({ globalPropIDs, modPropIDs })
if Modifiers.getModifierByID(modID) ~= nil then
-- Provided ID is a modifier ID (as opposed to an alias)
table.insert(modifierIDs, {
["id"] = modID,
["type"] = 'id',
["props"] = combinedProps
})
else
-- Assume modID is a modifier alias
if getOpposites then
local incModAlias, decModAlias = 'increased' .. modID, 'decreased' .. modID
local incMod, decMod = Modifiers.getModifierByAlias(incModAlias), Modifiers.getModifierByAlias(decModAlias)
-- If neither alias resolves to a modifier, then let user know this is invalid
if incMod == nil and decMod == nil then
error('No such modifier alias: ' .. modID, 2)
end
-- Don't include increased or decreased variants if they don't resolve to a modifier,
-- as doing so will generate an error about an invalid alias later
if incMod ~= nil then
table.insert(modifierIDs, {
["id"] = incModAlias,
["type"] = 'alias',
["props"] = combinedProps
})
end
if decMod ~= nil then
table.insert(modifierIDs, {
["id"] = decModAlias,
["type"] = 'alias',
["props"] = combinedProps
})
end
else
table.insert(modifierIDs, {
["id"] = modID,
["type"] = 'alias',
["props"] = combinedProps
})
end
end
end
local modifierCriteria = Modifiers.getMatchCriteriaFromIDs(modifierIDs)
local hasOtherModifiers = false
local modifierCount = Shared.tableCount(modifiers)
local getModText =
function(modifiers)
local matchedMods = Modifiers.getMatchingModifiers(modifiers, modifierCriteria)
local mainModText = Modifiers.getModifiersText(matchedMods.matched, true, false, maxOtherMods)
local otherModText = Modifiers.getModifiersText(matchedMods.unmatched, true, false, maxOtherMods)
return mainModText, otherModText, matchedMods
end
local tableArray = {}
--Going through each type of thing to add to the array
local itemList = p.getItemsWithModifier(modifierCriteria)
for i, item in ipairs(itemList) do
local row = {}
row.name = item.name
row.icon = Icons.Icon({item.name, type='item'})
row.expIcon = Icons.getDLCColumnIcon(item.id)
row.expSort = Icons.getExpansionID(item.id)
row.type = 'Item'
row.typeText = row.type
--For equipment, show the slot they go in
if item.validSlots ~= nil and not Shared.tableIsEmpty(item.validSlots) then
local rowTypePart = {}
for j, slot in ipairs(item.validSlots) do
table.insert(rowTypePart, Common.getEquipmentSlotLink(slot))
end
row.typeText = row.typeText .. ' (' .. table.concat(item.validSlots, ', ') .. ')'
row.type = row.type .. ' (' .. table.concat(rowTypePart, ', ') .. ')'
end
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(item.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local petList = p.getPetsWithModifier(modifierCriteria)
for i, pet in Shared.skpairs(petList) do
local row = {}
row.name = pet.name
row.icon = Icons.Icon({pet.name, type='pet'})
row.expIcon = Icons.getDLCColumnIcon(pet.id)
row.expSort = Icons.getExpansionID(pet.id)
row.type = '[[Pets|Pet]]'
row.typeText = 'Pet'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(pet.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local nodeList = p.getSkillTreeNodesWithModifier(modifierCriteria)
for _, node in ipairs(nodeList) do
local row = {}
row.name = node.skillName .. " - " .. node.name
local firstIcon = Icons.Icon({"", img='Skill Tree', nolink=true})
local secondIcon = Icons.Icon({node.skillName..'%23#Skill_Tree', node.name, type='skill', img=node.skillName})
row.icon = firstIcon .. " " .. secondIcon
row.expIcon = Icons.getDLCColumnIcon(node.id)
row.expSort = Icons.getExpansionID(node.id)
row.type = '[[Skill Tree#Nodes|Skill Tree Node]]'
row.typeText = 'Skill Tree Node'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(node.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local obstList = p.getObstaclesWithModifier(modifierCriteria)
table.sort(obstList, function(a, b) return a.category < b.category end)
for i, obst in Shared.skpairs(obstList) do
local row = {}
row.name = obst.name
row.icon = Icons.Icon({'Agility%23'..string.gsub(obst.name, ' ', ''), obst.name, type='skill', img='Agility'})
row.expIcon = Icons.getDLCColumnIcon(obst.id)
row.expSort = Icons.getExpansionID(obst.id)
row.type = '[[Agility#Obstacles|Agility Obstacle '..tostring(tonumber(obst.category)+1)..']]'
row.typeText = 'Agility Obstacle '..string.format("%02d", (obst.category + 1))
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(obst.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local pillarList = p.getPillarsWithModifier(modifierCriteria)
for i, pillar in ipairs(pillarList) do
local row = {}
row.name = pillar.name
row.icon = Icons.Icon({'Agility%23'..string.gsub(pillar.name, ' ', ''), pillar.name, type='skill', img='Agility'})
row.expIcon = Icons.getDLCColumnIcon(pillar.id)
row.expSort = Icons.getExpansionID(pillar.id)
row.type = '[[Agility#Passive Pillars|Agility Pillar]]'
row.typeText = 'Agility Pillar'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(pillar.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local prayerList = p.getPrayersWithModifier(modifierCriteria)
for i, prayer in ipairs(prayerList) do
local row = {}
row.name = prayer.name
row.icon = Icons.Icon({prayer.name, type='prayer'})
row.expIcon = Icons.getDLCColumnIcon(prayer.id)
row.expSort = Icons.getExpansionID(prayer.id)
row.type = [[Prayer]]
row.typeText = 'Prayer'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(prayer.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local upgradeList = p.getUpgradesWithModifier(modifierCriteria)
for i, upgrade in ipairs(upgradeList) do
local row = {}
row.name = Shop._getPurchaseName(upgrade)
row.icon = Icons.Icon({row.name, type='upgrade'})
row.expIcon = Icons.getDLCColumnIcon(upgrade.id)
row.expSort = Icons.getExpansionID(upgrade.id)
row.type = '[[Shop|Upgrade]]'
row.typeText = 'Upgrade'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(upgrade.contains.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local constellationList = p.getConstellationsWithModifier(modifierCriteria)
for i, cons in ipairs(constellationList) do
local modListByType = Skills._getConstellationModifiers(cons)
local modList = {}
-- Combine all mods into single list
for modType, modsForType in pairs(modListByType) do
for _, mod in ipairs(modsForType) do
if mod.modifiers ~= nil then
for modKey, modDefn in pairs(mod.modifiers) do
if type(modList[modKey]) == 'table' and modList[modKey][1] ~= nil then
for _, v in ipairs(modDefn) do
table.insert(modList[modKey], v)
end
else
modList[modKey] = modDefn
end
end
end
end
end
local row = {}
row.name = cons.name
row.icon = Icons.Icon({cons.name, type='constellation'})
row.expIcon = Icons.getDLCColumnIcon(cons.id)
row.expSort = Icons.getExpansionID(cons.id)
row.type = '[[Astrology#Constellations|Constellation]]'
row.typeText = 'Constellation'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(modList)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local POIList = p.getPOIsWithModifier(modifierCriteria)
for i, POI in ipairs(POIList) do
local row = {}
row.name = POI.name
row.icon = Icons.Icon({POI.name, type='poi'})
row.expIcon = Icons.getDLCColumnIcon(POI.id)
row.expSort = Icons.getExpansionID(POI.id)
row.type = '[[Cartography|Point of Interest]]'
row.typeText = 'Point of Interest'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(POI.activeStats.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local cartoBonusList = p.getCartoMasteryBonusesWithModifier(modifierCriteria)
for i, bonus in ipairs(cartoBonusList) do
local row = {}
row.name = Num.formatnum(bonus.masteredHexes) .. ' Hexes Mastered'
row.icon = Icons.Icon({'Cartography', Num.formatnum(bonus.masteredHexes) .. ' Hexes Mastered', type='skill'})
row.expIcon = Icons.getDLCColumnIcon(bonus.id)
row.expSort = Icons.getExpansionID(bonus.id)
row.type = Icons.Icon({'Cartography', 'Mastery Bonus', section='Mastery Unlocks', type='skill', noicon=true})
row.typeText = 'Mastery Bonus'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(bonus.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local ancientRelicList = p.getAncientRelicsWithModifiers(modifierCriteria)
for i, relic in ipairs(ancientRelicList) do
local row = {}
local relicName = relic.name
local sectionName = 'Melvor Realm'
if string.find(relic.id, 'Abyssal') ~= nil then
relicName = 'Abyssal ' .. relicName
sectionName = 'Abyssal Realm'
end
row.name = relicName
row.icon = Icons.Icon({'Ancient Relics', relicName, section=sectionName})
row.expIcon = Icons.getDLCColumnIcon(relic.id)
row.expSort = Icons.getExpansionID(relic.id)
row.type = Icons.Icon({'Ancient Relics', 'Ancient Relic', noicon=true})
row.typeText = 'Ancient Relic'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(relic.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local buildingList = p.getBuildingsWithModifiers(modifierCriteria)
for i, building in ipairs(buildingList) do
local row = {}
row.name = building.name
row.icon = Icons.Icon({building.name, type='building'})
row.expIcon = Icons.getDLCColumnIcon(building.id)
row.expSort = Icons.getExpansionID(building.id)
row.type = Icons.Icon({'Township', 'Building', section='Buildings', type='skill', noicon=true})
row.typeText = 'Building'
local modList = {}
-- Multiply mod value by max upgrades to get the total modifier value
for modID, value in pairs(building.modifiers) do
if type(value) == 'table' then
modList[modID] = value[1].value * building.maxUpgrades
else
modList[modID] = value * building.maxUpgrades
end
end
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(modList)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local seasonList = p.getSeasonsWithModifiers(modifierCriteria)
for i, season in ipairs(seasonList) do
local row = {}
row.name = season.name
row.icon = Icons.Icon({season.name, type='township'})
row.expIcon = Icons.getDLCColumnIcon(season.id)
row.expSort = Icons.getExpansionID(season.id)
row.type = Icons.Icon({'Township', 'Season', section='Seasons', type='skill', noicon=true})
row.typeText = 'Season'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(season.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local summoningSynergyList = p.getSummoningSynergiesWithModifiers(modifierCriteria)
for i, synergy in ipairs(summoningSynergyList) do
local row = {}
local famProduct1 = Summoning.getFamiliarRecipeByID(synergy.summonIDs[1])
local familiar1 = nil
local famProduct2 = Summoning.getFamiliarRecipeByID(synergy.summonIDs[2])
local familiar2 = nil
if famProduct1 ~= nil then
familiar1 = Items.getItemByID(famProduct1.productID)
end
if famProduct2 ~= nil then
familiar2 = Items.getItemByID(famProduct2.productID)
end
if familiar1 == nil or familiar2 == nil then
return
end
row.name = familiar1.name .. familiar2.name .. ' Synergy'
row.icon = Icons.Icon({familiar1.name, type='item'}) .. ' ' .. Icons.Icon({'SynergyIcon', notext=true, nolink=true}) .. ' ' .. Icons.Icon({familiar2.name, type='item'}) .. ' Synergy'
row.expIcon = Icons.getDLCColumnIcon(familiar2.id)
row.expSort = Icons.getExpansionID(familiar2.id)
row.type = Icons.Icon({'Summoning', 'Summoning Synergy', section='Synergies', type='skill', noicon=true})
row.typeText = 'Synergy'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(synergy.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
local masteryPools = p.getMasteryPoolModifiers(modifierCriteria)
for i, masteryPoolData in ipairs(masteryPools) do
for skillName, masteryPool in pairs(masteryPoolData) do
local row = {}
local isAbyssal = masteryPool.realm == 'melvorItA:Abyssal' and 'Abyssal ' or ''
row.name = isAbyssal .. masteryPool.percent .. '% Mastery Pool Bonus'
row.icon = Icons.Icon({skillName, row.name, section='Mastery Pool Checkpoints', type='skill'})
row.expIcon = Icons.getDLCColumnIcon(masteryPool.realm)
row.expSort = Icons.getExpansionID(masteryPool.realm)
row.type = Icons.Icon({skillName, 'Mastery Pool Bonus', section='Mastery Pool Checkpoints', type='skill', noicon=true})
row.typeText = 'Mastery Pool Bonus'
local objMods = nil
row.modifierText, row.otherModifiers, objMods = getModText(masteryPool.modifiers)
row.val = Modifiers.getModifierValue(objMods.matched)
if not hasOtherModifiers and not Shared.tableIsEmpty(objMods.unmatched) then
hasOtherModifiers = true
end
table.insert(tableArray, row)
end
end
local html = mw.html.create('table')
:addClass("wikitable sortable stickyHeader mw-collapsible")
if collapsed == true then
html:addClass("mw-collapsed")
end
local header = html:tag('tr'):addClass("headerRow-0")
header:tag('th'):wikitext('Source')
:tag('th'):wikitext('Type')
:tag('th'):wikitext('[[DLC]]')
:tag('th'):wikitext(columnName)
if hasOtherModifiers and displayOtherMods then
header:tag('th'):wikitext('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 or forceMagnitudeSort) and a.val ~= b.val then
return a.val > b.val
elseif a.typeText ~= b.typeText then
return a.typeText < b.typeText
else
return a.name < b.name
end
end)
for i, row in ipairs(tableArray) do
local datarow = html:tag('tr')
datarow:tag('td'):wikitext(row.icon)
:attr('data-sort-value', row.name)
datarow:tag('td'):wikitext(row.type)
:attr('data-sort-value', row.typeText)
datarow:tag('td'):wikitext(row.expIcon)
:css('text-align', 'center')
:attr('data-sort-value', row.expSort)
datarow:tag('td'):wikitext(row.modifierText)
:attr('data-sort-value', row.val)
if hasOtherModifiers and displayOtherMods then
datarow:tag('td'):wikitext(row.otherModifiers)
end
end
return tostring(html)
end
function p.getModifierTable(frame)
local args = frame.args ~= nil and frame.args or frame
local modifier = args[1]
local columnName = args[2]
local getOpposites = args[3]
local displayOtherMods = args.displayOtherMods
local maxOtherMods = tonumber(args.maxOtherMods) or 5
local forceMagnitudeSort = string.upper(tostring(args.forceMagnitudeSort)) == 'TRUE' or false
local globalPropsText = args.filters
local collapsed = string.upper(tostring(args.collapsed)) == 'TRUE' or false
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
-- Given a text string following format 'key1=val1;key2=val2;...', returns
-- a table: { key1 = val1, key2 = val2, ... }
local function modPropTextToTable(propText)
local propTable = {}
local propParts = Shared.splitString(propText, ';')
for _, propPart in ipairs(propParts) do
local valueStartIdx, _ = string.find(propPart, ':')
if valueStartIdx ~= nil then
local k = string.sub(propPart, 1, valueStartIdx - 1)
local v = string.sub(propPart, valueStartIdx + 1, -1)
propTable[k] = v
end
end
return propTable
end
local globalProps = {}
if globalPropsText ~= nil then
globalProps = modPropTextToTable(globalPropsText)
end
local modifierList = {}
local modifierListCrude = Shared.splitString(modifier, ',')
-- At this point, modifierListCrude requires further processing to separate modifier IDs
-- and properties
for _, modEntry in ipairs(modifierListCrude) do
local modID, modProps = nil, {}
local propStartIdx, _ = string.find(modEntry, '[[]') -- Matches plain text '['
if propStartIdx == nil then
-- No properties specified, the entire string is a modifier ID
modID = modEntry
else
modID = string.sub(modEntry, 1, propStartIdx - 1)
local modPropText = string.sub(modEntry, propStartIdx + 1, -2)
modProps = modPropTextToTable(modPropText)
end
table.insert(modifierList, {
["id"] = modID,
["props"] = modProps
})
end
return p._getModifierTable(modifierList, globalProps, columnName, getOpposites, displayOtherMods, maxOtherMods, forceMagnitudeSort, collapsed)
end
-- Function to list all available modifiers for the relevant templates.
function p.getAllModifiers()
local tabl = mw.html.create('table')
:addClass('mw-collapsible mw-collapsed')
tabl:tag('caption')
:css('min-width', '200px')
:tag('b')
:wikitext('All Modifiers List')
-- First, sort modifiers
local modifierNames = {}
for k, _ in pairs(Modifiers.ModifierIndex.localID) do
table.insert(modifierNames, k)
end
table.sort(modifierNames)
-- Then add modifiers to output table
for _, v in pairs(modifierNames) do
tabl:tag('tr')
:tag('td')
:tag('code')
:wikitext(tostring(v)):done()
:done()
:done()
end
return tostring(tabl)
end
--Function for console testing of modifier tables
function p.getModifierTableTest()
return p.getModifierTable({args = {'id:flatBaseRandomProductQuantity[item=Abyssal Stardust]', 'GP Boosts', filters = 'skill=Astrology'}})
end
return p