Module:ItemTables: Difference between revisions
Jump to navigation
Jump to search
add fire rate and stamina, include inclusions of different stat names, cleanup. WORKS NOW BUT ALSO BREAKS, invocations need to be reversed from internal to friendly, to friendly to internal |
m ...also add % suffix to Spirit Lifesteal |
||
(57 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
local get_cost = require("Module:ItemData")._get_cost | local get_cost = require("Module:ItemData")._get_cost | ||
local get_type = require("Module:ItemData")._get_type | local get_type = require("Module:ItemData")._get_type | ||
local commas = require("Module:Addcommas") | |||
-- | -- Returns an array of item tables that have the same properties | ||
function | -- @function get_similar_items_array | ||
-- @param {array} | |||
-- @return {array of tables} | |||
local function get_similar_items_array(property) | |||
local similarItems = {} | |||
local hash = {} | |||
local noDuplicates = {} | |||
for _, v in pairs(data) do | |||
for _, value in ipairs(property) do | |||
if (v[value] ~= nil and v["Disabled"] == false and v["Name"] ~= nil and v[value] ~= "0" and v[value] ~= "0m") then | |||
table.insert(similarItems, v) | |||
end | |||
end | |||
end | |||
-- remove duplicate items if that item contains multiple keys of the same stat increase (eg. Fleetfoot has both "BonusMoveSpeed", "ActiveBonusMoveSpeed" in move speed). | |||
-- there might be a more efficient way to prevent adding duplicate items in the first place in the above for loop | |||
for _, v in pairs(similarItems) do | |||
if (not hash[v]) then | |||
noDuplicates[#noDuplicates+1] = v | |||
hash[v] = true | |||
end | |||
end | |||
return noDuplicates | |||
end | end | ||
Line 33: | Line 49: | ||
return copy | return copy | ||
end | end | ||
-- local link_patterns = {} | -- local link_patterns = {} | ||
Line 55: | Line 70: | ||
-- end | -- end | ||
local | local friendly_to_internal = {} | ||
friendly_to_internal["ammo"] = { "BonusClipSizePercent", "BonusClipSize", "ActiveReloadPercent" } | |||
friendly_to_internal["weapon damage"] = { "BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded" } | |||
friendly_to_internal["spirit damage"] = { "ProcBonusMagicDamage" } | |||
friendly_to_internal["bullet shield health"] = { "BulletShieldMaxHealth", "BulletShieldOnCast", "SaviorBulletShieldHealth", "FlyingBulletShield", "VexBarrierBulletMaxHealth" } | |||
friendly_to_internal["spirit shield health"] = { "TechShieldMaxHealth", "TechShieldOnCast", "SaviorMagicShieldHealth", "FlyingTechShield", "VexBarrierTechMaxHealth" } | |||
friendly_to_internal["bullet resist"] = { "BulletResist", "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletResistPerStack" } | |||
friendly_to_internal["bullet resist reduction"] = { "BulletArmorReduction", "BulletResistReduction" } | |||
friendly_to_internal["spirit resist"] = { "TechResist" } | |||
friendly_to_internal["spirit resist reduction"] = { "TechArmorDamageReduction", "MagicResistReduction" } | |||
friendly_to_internal["bonus health"] = { "BonusHealth" } | |||
friendly_to_internal["health regen"] = { "BonusHealthRegen" } | |||
friendly_to_internal["max health regen"] = { "HealLifePercentOutOfCombat" } | |||
friendly_to_internal["fire rate"] = { "BonusFireRate", "FireRateWhenShielded", "FireRateBonus", "FervorFireRate", "AmbushBonusFireRate", "ActiveBonusFireRate" } | |||
friendly_to_internal["fire rate slow"] = { "FireRateSlow" } | |||
friendly_to_internal["bullet velocity"] = { "BonusBulletSpeedPercent" } | |||
friendly_to_internal["spirit power"] = { "TechPower", "BonusSpirit", "SpiritPower", "BonusSpiritWithMagicShield", "ImbuedTechPower", "AmbushBonusTechPower" } | |||
friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" } | |||
friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" } | |||
friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed" } | |||
friendly_to_internal["sprint speed"] = { "BonusSprintSpeed" } | |||
friendly_to_internal["movement slow"] = { "SlowPercent", "MovementSpeedSlow" } | |||
friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" } | |||
friendly_to_internal["heavy melee distance"] = { "MeleeDistanceScale" } | |||
friendly_to_internal["bonus heavy damage"] = { "BonusHeavyMeleeDamage" } | |||
friendly_to_internal["melee resist"] = { "MeleeResistPercent" } | |||
friendly_to_internal["stamina"] = { "Stamina" } | |||
friendly_to_internal["slide distance"] = { "SlideScale" } | |||
friendly_to_internal["stamina recovery"] = { "StaminaCooldownReduction" } | |||
friendly_to_internal["healing reduction"] = { "HealAmpRegenPenaltyPercent" } | |||
function | -- Returns a table of internal properties | ||
-- @function friendlyNames | |||
-- @param {string} | |||
-- @return {table} | |||
local function friendlyNames(desc) | |||
local keysTable = {} | local keysTable = {} | ||
desc = string.lower(desc or "") | desc = string.lower(desc or "") | ||
for link, patterns in pairs( | for link, patterns in pairs(friendly_to_internal) do | ||
if (desc == link) then keysTable = patterns end | |||
end | |||
return keysTable | |||
end | |||
local unitSuffix = { | |||
["%"] = { "BonusClipSizePercent", "ActiveReloadPercent", | |||
"BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded", | |||
"TechResist", "BulletResist", | |||
"BonusFireRate", "FireRateWhenShielded", "FervorFireRate", "FireRateBonus", "AmbushBonusFireRate", "ActiveBonusFireRate", "FireRateSlow", | |||
"LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletArmorReduction", "BulletResistReduction", "BulletResistPerStack", | |||
"TechArmorDamageReduction", "MagicResistReduction", | |||
"BonusBulletSpeedPercent", | |||
"BulletLifestealPercent", "ActiveBonusLifesteal", "AbilityLifestealPercentHero", | |||
"HealLifePercentOutOfCombat", | |||
"ReloadSpeedMultipler", | |||
"MeleeDistanceScale", "BonusHeavyMeleeDamage", "MeleeResistPercent", | |||
"SlideScale", | |||
"StaminaCooldownReduction", | |||
"SlowPercent", "MovementSpeedSlow", | |||
"HealAmpRegenPenaltyPercent" }, | |||
["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed" } | |||
} | |||
local function appendSuffix(internal) | |||
local unitName = "" | |||
for key, s in pairs(unitSuffix) do | |||
for _, pattern in pairs(s) do | |||
if (internal == pattern) then return key end | |||
end | |||
end | |||
return unitName | |||
end | |||
local sortByWeapon = {} | |||
sortByWeapon["Weapon"] = 1 | |||
sortByWeapon["Armor"] = 10000 | |||
sortByWeapon["Tech"] = 100000000 | |||
-- Sort the order of items in a preset as it appears when no filtered ordering is applied. | |||
-- Ordered first by slot and cost increasing, then alphabetical within same slot and cost. | |||
function defaultSort() | |||
return function(a, b) | |||
if (get_cost(a["Name"]) == get_cost(b["Name"]) and sortByWeapon[a["Slot"]] == sortByWeapon[b["Slot"]]) then return a["Name"] < b["Name"] end | |||
return get_cost(a["Name"]) * sortByWeapon[a["Slot"]] < get_cost(b["Name"]) * sortByWeapon[b["Slot"]] | |||
end | |||
end | |||
-- Formats the value of the stat with a + or - | |||
-- @function signPrefix | |||
-- @param {string} | |||
-- @return {string} | |||
local function signPrefix(value) | |||
local signString = "" | |||
value = value:gsub( "m", "" ) | |||
value = tonumber(value) | |||
if (value >= 0) then | |||
return "+<b>" .. value .. "</b>" | |||
elseif (value < 0) then | |||
value = math.abs(value) | |||
return "-<b>" .. value .. "</b>" | |||
end | end | ||
end | end | ||
-- Outputs a wikitable of items that increase a specified stat. Invoked by {{Item stat table}} | |||
-- @function p.itemPropTable | |||
-- @param {string} | |||
-- @return {string} | |||
p.itemPropTable = function(frame) | p.itemPropTable = function(frame) | ||
local requirements = {} | local requirements = {} | ||
local listofKeysTable = {} | local listofKeysTable = {} | ||
local listofItems = "" | local listofItems = "" | ||
local property = frame.args[1] or mw.title.getCurrentTitle().text | local property = frame:getParent().args[1] or mw.title.getCurrentTitle().text | ||
local copyVar = property | local copyVar = property | ||
listofKeysTable = | listofKeysTable = friendlyNames(property) | ||
local filteredData = {} | |||
filteredData = get_similar_items_array(listofKeysTable) | |||
table.sort(filteredData, defaultSort()) | |||
local createTable = mw.html.create('table') | local createTable = mw.html.create('table') | ||
:addClass('wikitable sortable') | :addClass('wikitable sortable') | ||
:tag('caption'):wikitext("List of | :tag('caption'):wikitext("List of items"):done() | ||
local | local soulIcon = frame:expandTemplate{ title = 'Souls' } | ||
local createTableHeader = mw.html.create('tr') | |||
createTableHeader | |||
:tag('th'):wikitext('Name'):done() | :tag('th'):wikitext('Name'):done() | ||
:tag('th'):wikitext('Cost'):done() | :tag('th'):wikitext(soulIcon .. 'Cost'):done() | ||
:tag('th'):wikitext('Category'):done() | :tag('th'):wikitext('Category'):done() | ||
:tag('th'):wikitext('Stat change'):done() | :tag('th'):wikitext('Stat change'):done() | ||
createTable:node( | createTable:node(createTableHeader) | ||
-- query all items | -- query all the filtered items. itemName is the item table. | ||
for internalName, itemName in | for internalName, itemName in ipairs(filteredData) do | ||
local display = frame:expandTemplate{ | local display = frame:expandTemplate{ | ||
Line 105: | Line 212: | ||
} | } | ||
} | } | ||
for | |||
-- filter out items that: don't have the property | for k, t in pairs(listofKeysTable) do | ||
if(itemName[t] ~= nil and itemName[ | -- filter out items that: don't have the property and the value isn't zero | ||
if(itemName[t] ~= nil and itemName[t] ~= "0" ) then | |||
listofItems = listofItems .. itemName["Name"] .. "<br/>" | listofItems = listofItems .. itemName["Name"] .. "<br/>" | ||
copyVar = copyVar:gsub("^%l", string.upper) | |||
local tableData = mw.html.create('tr') | local tableData = mw.html.create('tr') | ||
tableData | tableData | ||
:tag('td'):wikitext(display):done() | :tag('td'):wikitext(display):done() | ||
:tag('td'):wikitext(get_cost(itemName["Name"])):done() | :tag('td'):wikitext(commas._add(get_cost(itemName["Name"]))):done() | ||
:tag('td'):wikitext(get_type(itemName["Name"])):done() | :tag('td'):wikitext(get_type(itemName["Name"])):done() | ||
:tag('td'):wikitext(" | |||
if (t == "LocalBulletArmorReduction") then | |||
tableData | |||
:tag('td'):wikitext("<span style=\"color:red;\">" .. signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done() | |||
else | |||
tableData | |||
:tag('td'):wikitext(signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done() | |||
end | |||
table.insert(requirements, tableData) | table.insert(requirements, tableData) | ||
end | end | ||
end | end | ||
Line 124: | Line 239: | ||
for _, row in ipairs(requirements) do | for _, row in ipairs(requirements) do | ||
createTableHeader:node(row) | |||
end | end | ||
return tostring(createTable) | return tostring(createTable) --, listofItems -- this is just a string list, same thing as createTable. delete this when line when finished | ||
end | end | ||
return p | return p |
Latest revision as of 20:49, 12 November 2024
Documentation for this module may be created at Module:ItemTables/doc
local p = {};
local data = mw.loadJsonData("Data:ItemData.json")
local get_cost = require("Module:ItemData")._get_cost
local get_type = require("Module:ItemData")._get_type
local commas = require("Module:Addcommas")
-- Returns an array of item tables that have the same properties
-- @function get_similar_items_array
-- @param {array}
-- @return {array of tables}
local function get_similar_items_array(property)
local similarItems = {}
local hash = {}
local noDuplicates = {}
for _, v in pairs(data) do
for _, value in ipairs(property) do
if (v[value] ~= nil and v["Disabled"] == false and v["Name"] ~= nil and v[value] ~= "0" and v[value] ~= "0m") then
table.insert(similarItems, v)
end
end
end
-- remove duplicate items if that item contains multiple keys of the same stat increase (eg. Fleetfoot has both "BonusMoveSpeed", "ActiveBonusMoveSpeed" in move speed).
-- there might be a more efficient way to prevent adding duplicate items in the first place in the above for loop
for _, v in pairs(similarItems) do
if (not hash[v]) then
noDuplicates[#noDuplicates+1] = v
hash[v] = true
end
end
return noDuplicates
end
--- Copies original table with its children as deep as possible. Does not handle metatables. (Copy is needed because Lua passes by reference, not value)
-- @function Deepcopy
-- @param {n-D table}
-- @return {n-D table}
function Deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[Deepcopy(orig_key)] = Deepcopy(orig_value)
end
else
copy = orig
end
return copy
end
-- local link_patterns = {}
-- link_patterns["BonusClipSizePercent"] = { "[Aa]mmo" }
-- link_patterns["CloseRangeBonusWeaponPower"] = { "[Cc]lose [Ww]eapon [Dd]amage" }
-- link_patterns["BaseAttackDamagePercent"] = { "[Ww]eapon [Dd]amage" }
-- link_patterns["BulletLifestealPercent"] = { "[Bb]ullet [Ll]ifesteal" }
-- link_patterns["BonusHealthRegen"] = { "[Hh]ealth [Rr]egen" }
-- link_patterns["BonusHealth"] = { "[Hh]ealth" }
-- link_patterns["BonusFireRate"] = { "[Ff]ire [Rr]ate" }
--
-- function FriendlyNames(desc)
-- for link, patterns in pairs(link_patterns) do
-- for i, v in ipairs(patterns) do
-- local a = string.find(desc, v)
-- if a then desc = link break
-- end
-- end
-- end
-- return desc
-- end
local friendly_to_internal = {}
friendly_to_internal["ammo"] = { "BonusClipSizePercent", "BonusClipSize", "ActiveReloadPercent" }
friendly_to_internal["weapon damage"] = { "BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded" }
friendly_to_internal["spirit damage"] = { "ProcBonusMagicDamage" }
friendly_to_internal["bullet shield health"] = { "BulletShieldMaxHealth", "BulletShieldOnCast", "SaviorBulletShieldHealth", "FlyingBulletShield", "VexBarrierBulletMaxHealth" }
friendly_to_internal["spirit shield health"] = { "TechShieldMaxHealth", "TechShieldOnCast", "SaviorMagicShieldHealth", "FlyingTechShield", "VexBarrierTechMaxHealth" }
friendly_to_internal["bullet resist"] = { "BulletResist", "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletResistPerStack" }
friendly_to_internal["bullet resist reduction"] = { "BulletArmorReduction", "BulletResistReduction" }
friendly_to_internal["spirit resist"] = { "TechResist" }
friendly_to_internal["spirit resist reduction"] = { "TechArmorDamageReduction", "MagicResistReduction" }
friendly_to_internal["bonus health"] = { "BonusHealth" }
friendly_to_internal["health regen"] = { "BonusHealthRegen" }
friendly_to_internal["max health regen"] = { "HealLifePercentOutOfCombat" }
friendly_to_internal["fire rate"] = { "BonusFireRate", "FireRateWhenShielded", "FireRateBonus", "FervorFireRate", "AmbushBonusFireRate", "ActiveBonusFireRate" }
friendly_to_internal["fire rate slow"] = { "FireRateSlow" }
friendly_to_internal["bullet velocity"] = { "BonusBulletSpeedPercent" }
friendly_to_internal["spirit power"] = { "TechPower", "BonusSpirit", "SpiritPower", "BonusSpiritWithMagicShield", "ImbuedTechPower", "AmbushBonusTechPower" }
friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" }
friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" }
friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed" }
friendly_to_internal["sprint speed"] = { "BonusSprintSpeed" }
friendly_to_internal["movement slow"] = { "SlowPercent", "MovementSpeedSlow" }
friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" }
friendly_to_internal["heavy melee distance"] = { "MeleeDistanceScale" }
friendly_to_internal["bonus heavy damage"] = { "BonusHeavyMeleeDamage" }
friendly_to_internal["melee resist"] = { "MeleeResistPercent" }
friendly_to_internal["stamina"] = { "Stamina" }
friendly_to_internal["slide distance"] = { "SlideScale" }
friendly_to_internal["stamina recovery"] = { "StaminaCooldownReduction" }
friendly_to_internal["healing reduction"] = { "HealAmpRegenPenaltyPercent" }
-- Returns a table of internal properties
-- @function friendlyNames
-- @param {string}
-- @return {table}
local function friendlyNames(desc)
local keysTable = {}
desc = string.lower(desc or "")
for link, patterns in pairs(friendly_to_internal) do
if (desc == link) then keysTable = patterns end
end
return keysTable
end
local unitSuffix = {
["%"] = { "BonusClipSizePercent", "ActiveReloadPercent",
"BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded",
"TechResist", "BulletResist",
"BonusFireRate", "FireRateWhenShielded", "FervorFireRate", "FireRateBonus", "AmbushBonusFireRate", "ActiveBonusFireRate", "FireRateSlow",
"LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletArmorReduction", "BulletResistReduction", "BulletResistPerStack",
"TechArmorDamageReduction", "MagicResistReduction",
"BonusBulletSpeedPercent",
"BulletLifestealPercent", "ActiveBonusLifesteal", "AbilityLifestealPercentHero",
"HealLifePercentOutOfCombat",
"ReloadSpeedMultipler",
"MeleeDistanceScale", "BonusHeavyMeleeDamage", "MeleeResistPercent",
"SlideScale",
"StaminaCooldownReduction",
"SlowPercent", "MovementSpeedSlow",
"HealAmpRegenPenaltyPercent" },
["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed" }
}
local function appendSuffix(internal)
local unitName = ""
for key, s in pairs(unitSuffix) do
for _, pattern in pairs(s) do
if (internal == pattern) then return key end
end
end
return unitName
end
local sortByWeapon = {}
sortByWeapon["Weapon"] = 1
sortByWeapon["Armor"] = 10000
sortByWeapon["Tech"] = 100000000
-- Sort the order of items in a preset as it appears when no filtered ordering is applied.
-- Ordered first by slot and cost increasing, then alphabetical within same slot and cost.
function defaultSort()
return function(a, b)
if (get_cost(a["Name"]) == get_cost(b["Name"]) and sortByWeapon[a["Slot"]] == sortByWeapon[b["Slot"]]) then return a["Name"] < b["Name"] end
return get_cost(a["Name"]) * sortByWeapon[a["Slot"]] < get_cost(b["Name"]) * sortByWeapon[b["Slot"]]
end
end
-- Formats the value of the stat with a + or -
-- @function signPrefix
-- @param {string}
-- @return {string}
local function signPrefix(value)
local signString = ""
value = value:gsub( "m", "" )
value = tonumber(value)
if (value >= 0) then
return "+<b>" .. value .. "</b>"
elseif (value < 0) then
value = math.abs(value)
return "-<b>" .. value .. "</b>"
end
end
-- Outputs a wikitable of items that increase a specified stat. Invoked by {{Item stat table}}
-- @function p.itemPropTable
-- @param {string}
-- @return {string}
p.itemPropTable = function(frame)
local requirements = {}
local listofKeysTable = {}
local listofItems = ""
local property = frame:getParent().args[1] or mw.title.getCurrentTitle().text
local copyVar = property
listofKeysTable = friendlyNames(property)
local filteredData = {}
filteredData = get_similar_items_array(listofKeysTable)
table.sort(filteredData, defaultSort())
local createTable = mw.html.create('table')
:addClass('wikitable sortable')
:tag('caption'):wikitext("List of items"):done()
local soulIcon = frame:expandTemplate{ title = 'Souls' }
local createTableHeader = mw.html.create('tr')
createTableHeader
:tag('th'):wikitext('Name'):done()
:tag('th'):wikitext(soulIcon .. 'Cost'):done()
:tag('th'):wikitext('Category'):done()
:tag('th'):wikitext('Stat change'):done()
createTable:node(createTableHeader)
-- query all the filtered items. itemName is the item table.
for internalName, itemName in ipairs(filteredData) do
local display = frame:expandTemplate{
title = 'ItemIcon',
args = {
itemName["Name"]
}
}
for k, t in pairs(listofKeysTable) do
-- filter out items that: don't have the property and the value isn't zero
if(itemName[t] ~= nil and itemName[t] ~= "0" ) then
listofItems = listofItems .. itemName["Name"] .. "<br/>"
copyVar = copyVar:gsub("^%l", string.upper)
local tableData = mw.html.create('tr')
tableData
:tag('td'):wikitext(display):done()
:tag('td'):wikitext(commas._add(get_cost(itemName["Name"]))):done()
:tag('td'):wikitext(get_type(itemName["Name"])):done()
if (t == "LocalBulletArmorReduction") then
tableData
:tag('td'):wikitext("<span style=\"color:red;\">" .. signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done()
else
tableData
:tag('td'):wikitext(signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done()
end
table.insert(requirements, tableData)
end
end
end
for _, row in ipairs(requirements) do
createTableHeader:node(row)
end
return tostring(createTable) --, listofItems -- this is just a string list, same thing as createTable. delete this when line when finished
end
return p