Module:ItemTables: Difference between revisionsGive feedback
Jump to navigation
Jump to search
Instead of removing duplicates, keep all stats and use rowspan to merge the item info across multiple rows. Added FervorMovespeed to move speed |
m added InvisMoveSpeedMod to sprint speed |
||
| Line 46: | Line 46: | ||
friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" } | friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" } | ||
friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" } | friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" } | ||
friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "FervorMovespeed"} | friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "FervorMovespeed",} | ||
friendly_to_internal["sprint speed"] = { "BonusSprintSpeed" } | friendly_to_internal["sprint speed"] = { "BonusSprintSpeed", "InvisMoveSpeedMod" } | ||
friendly_to_internal["movement slow"] = { "SlowPercent", "MovementSpeedSlow" } | friendly_to_internal["movement slow"] = { "SlowPercent", "MovementSpeedSlow" } | ||
friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" } | friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" } | ||
| Line 111: | Line 111: | ||
"GroundDashReductionPercent" | "GroundDashReductionPercent" | ||
}, | }, | ||
["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed", "FervorMovespeed"}, | ["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed", "FervorMovespeed", "InvisMoveSpeedMod" }, | ||
[" HP"] = {"CombatBarrier", "GuardianWardCombatBarrier", "VexBarrierCombatBarrier"} | [" HP"] = {"CombatBarrier", "GuardianWardCombatBarrier", "VexBarrierCombatBarrier"} | ||
} | } | ||
Revision as of 18:04, 18 January 2026
Module used to create item tables with Template:Item stat table.
To add a new stat, add the name of the stat as "friendly to internal", followed by the property as listed on Data:ItemData.json, as well as adding the property to the "local unitSuffix" list corresponding to its suffix.
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")
--- 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 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["barrier"] = { "CombatBarrier", "GuardianWardCombatBarrier", "VexBarrierCombatBarrier" }
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["regeneration"] = { "Regeneration" }
friendly_to_internal["regeneration duration"] = { "RegenerationDuration" }
friendly_to_internal["out of combat health regen"] = { "OutOfCombatHealthRegen" }
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", "TechPowerPercent" }
friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" }
friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" }
friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "FervorMovespeed",}
friendly_to_internal["sprint speed"] = { "BonusSprintSpeed", "InvisMoveSpeedMod" }
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["bonus melee damage"] = { "BonusMeleeDamagePercent" }
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" }
friendly_to_internal["ability duration"] = { "ImbuedBonusDuration", "BonusAbilityDurationPercent" }
friendly_to_internal["ability cooldown reduction"] = { "ImbuedCooldownReduction", "CooldownReduction" }
friendly_to_internal["item cooldown reduction"] = { "ItemCooldownReduction" }
friendly_to_internal["charge cooldown reduction"] = { "CooldownReductionOnChargedAbilities" }
friendly_to_internal["debuff resist"] = { "StatusResistancePercent" }
friendly_to_internal["ability range"] = { "TechRangeMultiplier", "ImbuedTechRangeMultiplier"}
friendly_to_internal["falloff range"] = { "BonusAttackRangePercent" }
friendly_to_internal["spirit amp"] = { "ShreddersTechAmp", "MagicIncreasePerStack" }
friendly_to_internal["spirit damage reduction"] = { "TechDamageReduction" }
friendly_to_internal["dash distance"] = { "GroundDashReductionPercent" }
friendly_to_internal["damage reduction"] = { "OutgoingDamagePenaltyPercent", "DeathImmunityDamageReduction" }
-- 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", "BonusMeleeDamagePercent", "MeleeResistPercent",
"SlideScale",
"StaminaCooldownReduction",
"SlowPercent", "MovementSpeedSlow",
"HealAmpReceivePenaltyPercent", "HealAmpRegenPenaltyPercent",
"ImbuedBonusDuration", "NonImbuedBonusDuration", "BonusAbilityDurationPercent",
"ImbuedCooldownReduction", "CooldownReduction",
"ItemCooldownReduction",
"CooldownReductionOnChargedAbilities",
"StatusResistancePercent",
"TechRangeMultiplier", "ImbuedTechRangeMultiplier",
"BonusAttackRangePercent",
"ShreddersTechAmp", "BonusAmpPerHeadshot", "MagicIncreasePerStack",
"TechDamageReduction",
"OutgoingDamagePenaltyPercent", "DeathImmunityDamageReduction", "TechPowerPercent",
"GroundDashReductionPercent"
},
["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed", "FervorMovespeed", "InvisMoveSpeedMod" },
[" HP"] = {"CombatBarrier", "GuardianWardCombatBarrier", "VexBarrierCombatBarrier"}
}
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 a stat value with a leading + or - sign and makes it bold.
-- The function is robust and handles nil, number, string, or table inputs safely.
-- @function signPrefix
-- @param {any} The stat value to format.
-- @return {string} The formatted wikitext string.
local function signPrefix(value)
if value == nil then
return ""
end
value = tostring(value)
value = value:gsub("m", "")
value = tonumber(value)
if not value then
return ""
end
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 property = frame:getParent().args[1] or mw.title.getCurrentTitle().text
local copyVar = property
-- Get internal keys corresponding to the friendly property name
listofKeysTable = friendlyNames(property)
local filteredData = {}
for _, v in pairs(data) do
for _, t in ipairs(listofKeysTable) do
if v[t] ~= nil and v["IsDisabled"] == false and v["Name"] ~= nil and v[t] ~= "0" and v[t] ~= "0m" and v[t] ~= "" then
table.insert(filteredData, v)
break
end
end
end
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)
-- Track rowspans for items with multiple stats
local rowspanTracker = {}
for _, itemName in ipairs(filteredData) do
local display = frame:expandTemplate{
title = 'ItemIcon',
args = { itemName["Name"] }
}
local statCount = 0
for _, t in pairs(listofKeysTable) do
if(itemName[t] ~= nil and itemName[t] ~= "0") then
statCount = statCount + 1
end
end
if statCount == 0 then statCount = 1 end
rowspanTracker[itemName["Name"]] = statCount
local firstStat = true
for _, t in pairs(listofKeysTable) do
if(itemName[t] ~= nil and itemName[t] ~= "0") then
-- Handles complex stat values from the JSON data.
-- A stat can be a simple value (e.g., "BonusMoveSpeed": "1") or a table containing
-- scaling info (e.g., "BonusFireRate": { "Value": 10, "Scale": ... }).
-- This code checks if the stat is a table and extracts the base numerical value from its 'Value' key.
local statValue = itemName[t]
if type(statValue) == 'table' and statValue.Value ~= nil then
statValue = statValue.Value
end
copyVar = copyVar:gsub("^%l", string.upper)
local categoryDisplay
if itemName["Slot"] == "Armor" then
categoryDisplay = frame:expandTemplate{
title = 'ItemType',
args = { "Armor", "Vitality" }
}
elseif itemName["Slot"] == "Tech" then
categoryDisplay = frame:expandTemplate{
title = 'ItemType',
args = { "Tech", "Spirit" }
}
else
categoryDisplay = frame:expandTemplate{
title = 'ItemType',
args = { "Weapon", "Weapon" }
}
end
local tableData = mw.html.create('tr')
if firstStat then
tableData
:tag('td'):attr('rowspan', statCount):wikitext(display):done()
:tag('td'):attr('rowspan', statCount):wikitext(commas._add(get_cost(itemName["Name"]))):done()
:tag('td'):attr('rowspan', statCount):wikitext(categoryDisplay):done()
firstStat = false
end
tableData:tag('td'):wikitext(signPrefix(statValue) .. appendSuffix(t) .. " " .. copyVar):done()
table.insert(requirements, tableData)
end
end
end
for _, row in ipairs(requirements) do
createTable:node(row)
end
return tostring(createTable)
end
return p