Module:ItemTables: Difference between revisionsGive feedback
Added spirit power percent stat for spirit power table and added it to use a percent symbol in tables. |
Gammaton32 (talk | contribs) capacitor move slow |
||
| (31 intermediate revisions by 5 users not shown) | |||
| Line 1: | Line 1: | ||
local p = {}; | local p = {}; | ||
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") | local commas = require("Module:Addcommas") | ||
local GameData = require("Module:GameData") | |||
-- | -- Translate internal attribute names to plain text for module calls | ||
local friendly_to_internal = {} | local friendly_to_internal = {} | ||
friendly_to_internal["ammo"] = { "BonusClipSizePercent", "BonusClipSize", "ActiveReloadPercent" } | friendly_to_internal["ammo"] = { "BonusClipSizePercent", "BonusClipSize", "ActiveReloadPercent" } | ||
| Line 56: | Line 12: | ||
friendly_to_internal["bullet shield health"] = { "BulletShieldMaxHealth", "BulletShieldOnCast", "SaviorBulletShieldHealth", "FlyingBulletShield", "VexBarrierBulletMaxHealth" } | 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["spirit shield health"] = { "TechShieldMaxHealth", "TechShieldOnCast", "SaviorMagicShieldHealth", "FlyingTechShield", "VexBarrierTechMaxHealth" } | ||
friendly_to_internal["barrier"] = { "CombatBarrier" } | friendly_to_internal["barrier"] = { "CombatBarrier", "GuardianWardCombatBarrier", "VexBarrierCombatBarrier" } | ||
friendly_to_internal["bullet resist"] = { "BulletResist", "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletResistPerStack" } | friendly_to_internal["bullet resist"] = { "BulletResist", "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletResistPerStack" } | ||
friendly_to_internal["bullet resist reduction"] = { "BulletArmorReduction", "BulletResistReduction" } | friendly_to_internal["bullet resist reduction"] = { "BulletArmorReduction", "BulletResistReduction" } | ||
| Line 62: | Line 18: | ||
friendly_to_internal["spirit resist reduction"] = { "TechArmorDamageReduction", "MagicResistReduction" } | friendly_to_internal["spirit resist reduction"] = { "TechArmorDamageReduction", "MagicResistReduction" } | ||
friendly_to_internal["bonus health"] = { "BonusHealth" } | friendly_to_internal["bonus health"] = { "BonusHealth" } | ||
friendly_to_internal["bonus base health"] = { "BonusBaseHealth", "MaxHealthLossPercent" } | |||
friendly_to_internal["health regen"] = { "BonusHealthRegen" } | friendly_to_internal["health regen"] = { "BonusHealthRegen" } | ||
friendly_to_internal["regeneration"] = { "Regeneration" } | friendly_to_internal["regeneration"] = { "Regeneration" } | ||
| Line 67: | Line 24: | ||
friendly_to_internal["out of combat health regen"] = { "OutOfCombatHealthRegen" } | friendly_to_internal["out of combat health regen"] = { "OutOfCombatHealthRegen" } | ||
friendly_to_internal["max health regen"] = { "HealLifePercentOutOfCombat" } | friendly_to_internal["max health regen"] = { "HealLifePercentOutOfCombat" } | ||
friendly_to_internal["fire rate"] = { "BonusFireRate", "FireRateWhenShielded", "FireRateBonus", "FervorFireRate", "AmbushBonusFireRate", "ActiveBonusFireRate" } | friendly_to_internal["fire rate"] = { "BonusFireRate", "FireRateWhenShielded", "FireRateBonus", "FervorFireRate", "AmbushBonusFireRate", "ActiveBonusFireRate", "ActivatedFireRate" } | ||
friendly_to_internal["fire rate slow"] = { "FireRateSlow" } | friendly_to_internal["fire rate slow"] = { "FireRateSlow" } | ||
friendly_to_internal["bullet velocity"] = { "BonusBulletSpeedPercent" } | friendly_to_internal["bullet velocity"] = { "BonusBulletSpeedPercent" } | ||
| Line 73: | Line 30: | ||
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" } | 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", "MaxSlowPercent" } | ||
friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" } | friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" } | ||
friendly_to_internal["heavy melee distance"] = { "MeleeDistanceScale" } | friendly_to_internal["heavy melee distance"] = { "MeleeDistanceScale" } | ||
friendly_to_internal["bonus heavy damage"] = { "BonusHeavyMeleeDamage" } | friendly_to_internal["bonus heavy damage"] = { "BonusHeavyMeleeDamage" } | ||
friendly_to_internal["bonus melee damage"] = { "BonusMeleeDamagePercent" } | friendly_to_internal["bonus melee damage"] = { "BonusMeleeDamagePercent", "AmbushBonusMeleeDamage" } | ||
friendly_to_internal["melee resist"] = { "MeleeResistPercent" } | friendly_to_internal["melee resist"] = { "MeleeResistPercent" } | ||
friendly_to_internal["stamina"] = { "Stamina" } | friendly_to_internal["stamina"] = { "Stamina" } | ||
friendly_to_internal["slide distance"] = { "SlideScale" } | friendly_to_internal["slide distance"] = { "SlideScale" } | ||
friendly_to_internal["stamina recovery"] = { "StaminaCooldownReduction" } | friendly_to_internal["stamina recovery"] = { "StaminaCooldownReduction" } | ||
friendly_to_internal["healing reduction"] = { " | friendly_to_internal["healing reduction"] = { "HealAmpRegenPenaltyPercent" } | ||
friendly_to_internal["ability duration"] = { "ImbuedBonusDuration", "BonusAbilityDurationPercent" } | friendly_to_internal["ability duration"] = { "ImbuedBonusDuration", "BonusAbilityDurationPercent" } | ||
friendly_to_internal["cooldown reduction"] = { "ImbuedCooldownReduction", "CooldownReduction" } | 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["charge cooldown reduction"] = { "CooldownReductionOnChargedAbilities" } | ||
friendly_to_internal["debuff resist"] = { "StatusResistancePercent" } | friendly_to_internal["debuff resist"] = { "StatusResistancePercent", "FervorStatusResistancePercent" } | ||
friendly_to_internal["ability range"] = { "TechRangeMultiplier", "ImbuedTechRangeMultiplier"} | friendly_to_internal["ability range"] = { "TechRangeMultiplier", "ImbuedTechRangeMultiplier"} | ||
friendly_to_internal["falloff range"] = { "BonusAttackRangePercent" } | friendly_to_internal["falloff range"] = { "BonusAttackRangePercent" } | ||
friendly_to_internal["spirit amp"] = { "ShreddersTechAmp", "MagicIncreasePerStack" } | friendly_to_internal["spirit amp"] = { "ShreddersTechAmp", "MagicIncreasePerStack" } | ||
friendly_to_internal["spirit damage reduction"] = { "TechDamageReduction" } | friendly_to_internal["spirit damage reduction"] = { "TechDamageReduction" } | ||
friendly_to_internal["dash distance"] = { "GroundDashReductionPercent", "AirMoveIncreasePercent" } | |||
friendly_to_internal["damage reduction"] = { "OutgoingDamagePenaltyPercent", "DeathImmunityDamageReduction" } | friendly_to_internal["damage reduction"] = { "OutgoingDamagePenaltyPercent", "DeathImmunityDamageReduction" } | ||
friendly_to_internal["gravity scale"] = { "GravityScale" } | |||
-- Override dead/hidden stats that exist in data but don't actually work in‑game. | |||
-- Keys are item Names, values are tables of { [internalStatName] = replacementValue } | |||
local deadStatOverrides = { | |||
["Witchmail"] = { CooldownReduction = "0" }, | |||
["Refresher"] = { BulletResist = "0", TechResist = "0" }, | |||
["Glass Cannon"] = { SlowPercent = "0", MovementSpeedSlow = "0" }, | |||
["Majestic Leap"] = { SlowPercent = "0", MovementSpeedSlow = "0" }, | |||
["Improved Spirit"] = { BonusSprintSpeed = "0"}, | |||
} | |||
--- 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 | |||
-- Helper to resolve a stat value, applying any dead‑stat override if defined. | |||
local function resolveStatValue(itemName, t) | |||
if deadStatOverrides[itemName.Name] and deadStatOverrides[itemName.Name][t] ~= nil then | |||
return deadStatOverrides[itemName.Name][t] | |||
end | |||
return itemName[t] | |||
end | |||
-- Returns a table of internal properties | -- Returns a table of internal properties | ||
| Line 112: | Line 108: | ||
"BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded", | "BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded", | ||
"TechResist", "BulletResist", | "TechResist", "BulletResist", | ||
"BonusFireRate", "FireRateWhenShielded", "FervorFireRate", "FireRateBonus", "AmbushBonusFireRate", "ActiveBonusFireRate", "FireRateSlow", | "BonusFireRate", "FireRateWhenShielded", "FervorFireRate", "FireRateBonus", "AmbushBonusFireRate", "ActiveBonusFireRate", "ActivatedFireRate", "FireRateSlow", | ||
"LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletArmorReduction", "BulletResistReduction", "BulletResistPerStack", | "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletArmorReduction", "BulletResistReduction", "BulletResistPerStack", | ||
"TechArmorDamageReduction", "MagicResistReduction", | "TechArmorDamageReduction", "MagicResistReduction", | ||
| Line 119: | Line 115: | ||
"HealLifePercentOutOfCombat", | "HealLifePercentOutOfCombat", | ||
"ReloadSpeedMultipler", | "ReloadSpeedMultipler", | ||
"MeleeDistanceScale", "BonusHeavyMeleeDamage", "BonusMeleeDamagePercent", "MeleeResistPercent", | "MeleeDistanceScale", "BonusHeavyMeleeDamage", "BonusMeleeDamagePercent", "MeleeResistPercent", "AmbushBonusMeleeDamage", | ||
"SlideScale", | "SlideScale", | ||
"StaminaCooldownReduction", | "StaminaCooldownReduction", | ||
"SlowPercent", "MovementSpeedSlow", | "SlowPercent", "MovementSpeedSlow", "MaxSlowPercent", | ||
"HealAmpReceivePenaltyPercent", | "HealAmpReceivePenaltyPercent", "HealAmpRegenPenaltyPercent", | ||
"ImbuedBonusDuration", "NonImbuedBonusDuration", "BonusAbilityDurationPercent", | "ImbuedBonusDuration", "NonImbuedBonusDuration", "BonusAbilityDurationPercent", | ||
"ImbuedCooldownReduction", "CooldownReduction", | "ImbuedCooldownReduction", "CooldownReduction", | ||
"ItemCooldownReduction", | |||
"CooldownReductionOnChargedAbilities", | "CooldownReductionOnChargedAbilities", | ||
"StatusResistancePercent", | "StatusResistancePercent", | ||
| Line 132: | Line 129: | ||
"ShreddersTechAmp", "BonusAmpPerHeadshot", "MagicIncreasePerStack", | "ShreddersTechAmp", "BonusAmpPerHeadshot", "MagicIncreasePerStack", | ||
"TechDamageReduction", | "TechDamageReduction", | ||
"OutgoingDamagePenaltyPercent", "DeathImmunityDamageReduction", "TechPowerPercent" | "OutgoingDamagePenaltyPercent", "DeathImmunityDamageReduction", "TechPowerPercent", | ||
"GroundDashReductionPercent", "AirMoveIncreasePercent", | |||
"GravityScale", | |||
"BonusBaseHealth", "MaxHealthLossPercent" | |||
}, | }, | ||
["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed" }, | ["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed", "FervorMovespeed", "InvisMoveSpeedMod" }, | ||
[" HP"] = {"CombatBarrier"} | [" HP"] = {"CombatBarrier", "GuardianWardCombatBarrier", "VexBarrierCombatBarrier"} | ||
} | } | ||
| Line 162: | Line 162: | ||
end | end | ||
-- Formats | -- 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 | -- @function signPrefix | ||
-- @param { | -- @param {any} The stat value to format. | ||
-- @return {string} | -- @return {string} The formatted wikitext string. | ||
local function signPrefix(value) | local function signPrefix(value) | ||
if value == nil then | |||
value = value:gsub( "m", "" ) | return "" | ||
end | |||
value = tostring(value) | |||
value = value:gsub("m", "") | |||
value = tonumber(value) | value = tonumber(value) | ||
if not value then | |||
return "" | |||
end | |||
if (value >= 0) then | if (value >= 0) then | ||
return "+<b>" .. value .. "</b>" | return "+<b>" .. value .. "</b>" | ||
| Line 185: | Line 192: | ||
local requirements = {} | local requirements = {} | ||
local listofKeysTable = {} | local listofKeysTable = {} | ||
local property = frame:getParent().args[1] or mw.title.getCurrentTitle().text | local property = frame:getParent().args[1] or mw.title.getCurrentTitle().text | ||
local copyVar = property | local copyVar = property | ||
-- Get internal keys corresponding to the friendly property name | |||
listofKeysTable = friendlyNames(property) | listofKeysTable = friendlyNames(property) | ||
local filteredData = | |||
local filteredData = GameData.get_entities(GameData.Dataset.ITEMS, listofKeysTable) | |||
table.sort(filteredData, defaultSort()) | table.sort(filteredData, defaultSort()) | ||
local createTable = mw.html.create('table') | local createTable = mw.html.create('table') | ||
:addClass('wikitable sortable item-stat-table') | |||
:tag('caption'):done() | |||
local soulIcon = frame:expandTemplate{ title = 'Souls' } | local soulIcon = frame:expandTemplate{ title = 'Souls' } | ||
local createTableHeader = mw.html.create('tr') | local createTableHeader = mw.html.create('tr') | ||
createTableHeader | createTableHeader | ||
| Line 205: | Line 213: | ||
:tag('th'):wikitext('Category'):done() | :tag('th'):wikitext('Category'):done() | ||
:tag('th'):wikitext('Stat change'):done() | :tag('th'):wikitext('Stat change'):done() | ||
createTable:node(createTableHeader) | createTable:node(createTableHeader) | ||
-- | -- Track rowspans for items with multiple stats | ||
for | local rowspanTracker = {} | ||
for _, itemName in ipairs(filteredData) do | |||
local display = frame:expandTemplate{ | local display = frame:expandTemplate{ | ||
title = 'ItemIcon', | title = 'ItemIcon', | ||
args = { | args = { itemName["Name"] } | ||
} | } | ||
for | local statCount = 0 | ||
for _, t in pairs(listofKeysTable) do | |||
if( | local statVal = resolveStatValue(itemName, t) | ||
if(statVal ~= nil and statVal ~= "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 | |||
local statValue = resolveStatValue(itemName, t) | |||
if(statValue ~= nil and statValue ~= "0") then | |||
-- Handles complex stat values from the JSON data. | |||
if type(statValue) == 'table' and statValue.Value ~= nil then | |||
statValue = statValue.Value | |||
end | |||
copyVar = copyVar:gsub("^%l", string.upper) | copyVar = copyVar:gsub("^%l", string.upper) | ||
local categoryDisplay | local categoryDisplay | ||
if itemName["Slot"] == "Armor" then | if itemName["Slot"] == "Armor" then | ||
| Line 235: | Line 256: | ||
args = { "Tech", "Spirit" } | args = { "Tech", "Spirit" } | ||
} | } | ||
else | else | ||
categoryDisplay = frame:expandTemplate{ | categoryDisplay = frame:expandTemplate{ | ||
title = 'ItemType', | title = 'ItemType', | ||
| Line 241: | Line 262: | ||
} | } | ||
end | end | ||
local tableData = mw.html.create('tr') | local tableData = mw.html.create('tr') | ||
tableData | |||
if firstStat then | |||
tableData | |||
:tag('td'):attr('rowspan', statCount):wikitext(display):done() | |||
:tag('td'):attr('rowspan', statCount):wikitext( | |||
(get_cost(itemName["Name"]) == 9999) | |||
and "Legendary" | |||
or 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) | table.insert(requirements, tableData) | ||
end | end | ||
end | end | ||
end | end | ||
for _, row in ipairs(requirements) do | |||
createTable:node(row) | |||
end | |||
local edit_url = mw.uri.fullUrl("Module:ItemTables", { action = "edit" }) | |||
local disclaimer = frame:preprocess( | |||
'<div class="item-stat-table-disclaimer">' | |||
.. 'This is a dynamic list ' | |||
.. '<span class="item-stat-table-list-name">"' .. property .. '"</span>. ' | |||
.. '[' .. tostring(edit_url) .. ' Edit contents].' | |||
.. '</div>' | |||
) | |||
return disclaimer .. tostring(createTable) | |||
end | end | ||
return p | return p | ||