From Arms of God Wiki
bot: operator iteration 2026-06-10d (hover tooltips / filter chips + DPS sort / damage-type hubs / stat reverse-lookup pages) |
bot: documentation pass — editor-facing docs (data descriptions, module comments, template usage, Help rewrite) |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- Module:StatIndex — stat reverse-lookup | -- Module:StatIndex — "what modifies this stat?" reverse lookups. | ||
-- | -- | ||
-- | -- WHAT IT DOES | ||
-- Renders the lookup tables on the per-stat pages (Armor, Speed, ...) | |||
-- | -- and the damage-type hubs (Holy/Fire/Electric Damage). Nothing is | ||
-- stored: it scans the stat-bearing source Data pages at render time, | |||
-- | -- so a balance change edited into a Data page updates every stat page | ||
-- | -- on purge. | ||
-- | |||
-- HOW TO INVOKE | |||
-- {{#invoke:StatIndex|boosters|Armor}} every hero / blessing / | |||
-- upgrade / passive / Crux power modifying the stat (desc by amount) | |||
-- {{#invoke:StatIndex|weapons|Fire Damage}} every weapon dealing the | |||
-- elemental damage type (desc by amount) | |||
-- | |||
-- SOURCE DATA IT READS (via Module:Core) | |||
-- boosters: Data:Characters.json, Data:Blessings.json, | |||
-- Data:Upgrades.json, Data:Passives.json, Data:Crux.json. | |||
-- weapons: Data:Weapons.json. | |||
local Core = require('Module:Core') | |||
local p = {} | local p = {} | ||
| Line 12: | Line 24: | ||
local TH = '! style="background:var(--table-header-bg, #26272e);color:var(--infobox-header-fg, #f1e9d2);" | ' | local TH = '! style="background:var(--table-header-bg, #26272e);color:var(--infobox-header-fg, #f1e9d2);" | ' | ||
-- | -- Same mechanic, two data names: fold 'Explosive Range' into the | ||
local function | -- 'Explosive Radius' lookup key (and vice versa when querying either). | ||
local ALIAS_GROUPS = { | |||
['Explosive Radius'] = {'Explosive Radius', 'Explosive Range'}, | |||
['Explosive Range'] = {'Explosive Radius', 'Explosive Range'}, | |||
} | |||
local MODIFIER_CATS = {'Characters', 'Blessings', 'Upgrades', 'Passives', 'Crux'} | |||
local function statKeysFor(query) | |||
return ALIAS_GROUPS[query] or {query} | |||
end | |||
-- Internal: list of booster entries for a stat key. {rec, cat, tier, value, sort} | |||
function p._boosters(key) | |||
local keys = statKeysFor(key) | |||
local out = {} | local out = {} | ||
for k | for _, cat in ipairs(MODIFIER_CATS) do | ||
for _, rec in ipairs(Core.load(cat)) do | |||
local st = rec.stats or {} | |||
for _, k in ipairs(keys) do | |||
local v = st[k] | |||
if v ~= nil then | |||
local val = Core.fmtStat(v, true) | |||
if val ~= nil then | |||
local tier = rec.tier or rec.type or '' | |||
out[#out + 1] = { | |||
rec = rec, cat = cat, tier = tostring(tier), | |||
value = val, sort = Core.numStat(v) or 0, | |||
} | |||
end | |||
end | |||
end | |||
end | |||
end | |||
table.sort(out, function(a, b) | |||
if a.sort ~= b.sort then return a.sort > b.sort end | |||
return mw.ustring.lower(a.rec.name or '') < mw.ustring.lower(b.rec.name or '') | |||
end) | |||
return out | return out | ||
end | end | ||
-- Internal: list of weapons dealing an elemental damage type. | |||
local | function p._weapons(key) | ||
local out = {} | |||
for _, rec in ipairs(Core.load('Weapons')) do | |||
local v = Core.numStat((rec.stats or {})[key]) | |||
if v ~= nil and v > 0 and v < 1000 then | |||
local | out[#out + 1] = { | ||
rec = rec, class = Core.weaponClass(rec), | |||
tier = tostring(rec.tier or ''), value = Core.fmtNum(v), sort = v, | |||
} | |||
end | |||
end | end | ||
table.sort(out, function(a, b) | |||
if a.sort ~= b.sort then return a.sort > b.sort end | |||
return mw.ustring.lower(a.rec.name or '') < mw.ustring.lower(b.rec.name or '') | |||
end) | |||
return out | |||
end | end | ||
| Line 45: | Line 92: | ||
function p.boosters(frame) | function p.boosters(frame) | ||
local key = arg1(frame) | local key = arg1(frame) | ||
local list = p._boosters(key) | |||
local list = | if #list == 0 then | ||
if | |||
return "''No heroes, blessings, upgrades, passives or Crux powers " .. | return "''No heroes, blessings, upgrades, passives or Crux powers " .. | ||
"modify this stat in the current game data.''" | "modify this stat in the current game data.''" | ||
end | end | ||
local out = { TBL, '|-', | local out = { TBL, '|-', | ||
TH .. 'Source', TH .. 'Category', TH .. 'Tier / Type', TH .. 'Amount' } | TH .. 'Source', TH .. 'Category', TH .. 'Tier / Type', TH .. 'Amount' } | ||
for _, e in ipairs(list) do | for _, e in ipairs(list) do | ||
out[#out+1] = '|-' | out[#out+1] = '|-' | ||
out[#out+1] = '| ' .. | out[#out+1] = '| ' .. Core.iconLink(e.rec, 24) | ||
out[#out+1] = '| ' .. | out[#out+1] = '| ' .. e.cat | ||
out[#out+1] = '| ' .. (( | out[#out+1] = '| ' .. ((e.tier ~= '') and e.tier or '—') | ||
out[#out+1] = '| data-sort-value="' .. tostring(e.sort | out[#out+1] = '| data-sort-value="' .. tostring(e.sort) .. '" | ' .. e.value | ||
end | end | ||
out[#out+1] = '|}' | out[#out+1] = '|}' | ||
| Line 68: | Line 112: | ||
function p.weapons(frame) | function p.weapons(frame) | ||
local key = arg1(frame) | local key = arg1(frame) | ||
local list = p._weapons(key) | |||
local list = | if #list == 0 then | ||
if | |||
return "''No weapons deal this damage type in the current game data.''" | return "''No weapons deal this damage type in the current game data.''" | ||
end | end | ||
local out = { TBL, '|-', | local out = { TBL, '|-', | ||
TH .. 'Weapon', TH .. 'Class', TH .. 'Tier', TH .. key } | TH .. 'Weapon', TH .. 'Class', TH .. 'Tier', TH .. key } | ||
for _, e in ipairs(list) do | for _, e in ipairs(list) do | ||
out[#out+1] = '|-' | out[#out+1] = '|-' | ||
out[#out+1] = '| ' .. | out[#out+1] = '| ' .. Core.iconLink(e.rec, 24) | ||
out[#out+1] = '| ' .. | out[#out+1] = '| ' .. e.class | ||
out[#out+1] = '| ' .. | out[#out+1] = '| ' .. e.tier | ||
out[#out+1] = '| data-sort-value="' .. tostring(e.sort | out[#out+1] = '| data-sort-value="' .. tostring(e.sort) .. '" | ' .. e.value | ||
end | end | ||
out[#out+1] = '|}' | out[#out+1] = '|}' | ||
Latest revision as of 16:04, 10 June 2026
Documentation for this module may be created at Module:StatIndex/doc
-- Module:StatIndex — "what modifies this stat?" reverse lookups.
--
-- WHAT IT DOES
-- Renders the lookup tables on the per-stat pages (Armor, Speed, ...)
-- and the damage-type hubs (Holy/Fire/Electric Damage). Nothing is
-- stored: it scans the stat-bearing source Data pages at render time,
-- so a balance change edited into a Data page updates every stat page
-- on purge.
--
-- HOW TO INVOKE
-- {{#invoke:StatIndex|boosters|Armor}} every hero / blessing /
-- upgrade / passive / Crux power modifying the stat (desc by amount)
-- {{#invoke:StatIndex|weapons|Fire Damage}} every weapon dealing the
-- elemental damage type (desc by amount)
--
-- SOURCE DATA IT READS (via Module:Core)
-- boosters: Data:Characters.json, Data:Blessings.json,
-- Data:Upgrades.json, Data:Passives.json, Data:Crux.json.
-- weapons: Data:Weapons.json.
local Core = require('Module:Core')
local p = {}
local TBL = '{| class="wikitable sortable" style="font-size:0.95em;background:var(--table-row-odd, #1b1c20);color:var(--table-text, #e6e6e6);border-color:var(--table-border, #3a3c44);"'
local TH = '! style="background:var(--table-header-bg, #26272e);color:var(--infobox-header-fg, #f1e9d2);" | '
-- Same mechanic, two data names: fold 'Explosive Range' into the
-- 'Explosive Radius' lookup key (and vice versa when querying either).
local ALIAS_GROUPS = {
['Explosive Radius'] = {'Explosive Radius', 'Explosive Range'},
['Explosive Range'] = {'Explosive Radius', 'Explosive Range'},
}
local MODIFIER_CATS = {'Characters', 'Blessings', 'Upgrades', 'Passives', 'Crux'}
local function statKeysFor(query)
return ALIAS_GROUPS[query] or {query}
end
-- Internal: list of booster entries for a stat key. {rec, cat, tier, value, sort}
function p._boosters(key)
local keys = statKeysFor(key)
local out = {}
for _, cat in ipairs(MODIFIER_CATS) do
for _, rec in ipairs(Core.load(cat)) do
local st = rec.stats or {}
for _, k in ipairs(keys) do
local v = st[k]
if v ~= nil then
local val = Core.fmtStat(v, true)
if val ~= nil then
local tier = rec.tier or rec.type or ''
out[#out + 1] = {
rec = rec, cat = cat, tier = tostring(tier),
value = val, sort = Core.numStat(v) or 0,
}
end
end
end
end
end
table.sort(out, function(a, b)
if a.sort ~= b.sort then return a.sort > b.sort end
return mw.ustring.lower(a.rec.name or '') < mw.ustring.lower(b.rec.name or '')
end)
return out
end
-- Internal: list of weapons dealing an elemental damage type.
function p._weapons(key)
local out = {}
for _, rec in ipairs(Core.load('Weapons')) do
local v = Core.numStat((rec.stats or {})[key])
if v ~= nil and v > 0 and v < 1000 then
out[#out + 1] = {
rec = rec, class = Core.weaponClass(rec),
tier = tostring(rec.tier or ''), value = Core.fmtNum(v), sort = v,
}
end
end
table.sort(out, function(a, b)
if a.sort ~= b.sort then return a.sort > b.sort end
return mw.ustring.lower(a.rec.name or '') < mw.ustring.lower(b.rec.name or '')
end)
return out
end
local function arg1(frame)
local k = frame.args[1] or ''
return (k:gsub('^%s+', ''):gsub('%s+$', ''))
end
function p.boosters(frame)
local key = arg1(frame)
local list = p._boosters(key)
if #list == 0 then
return "''No heroes, blessings, upgrades, passives or Crux powers " ..
"modify this stat in the current game data.''"
end
local out = { TBL, '|-',
TH .. 'Source', TH .. 'Category', TH .. 'Tier / Type', TH .. 'Amount' }
for _, e in ipairs(list) do
out[#out+1] = '|-'
out[#out+1] = '| ' .. Core.iconLink(e.rec, 24)
out[#out+1] = '| ' .. e.cat
out[#out+1] = '| ' .. ((e.tier ~= '') and e.tier or '—')
out[#out+1] = '| data-sort-value="' .. tostring(e.sort) .. '" | ' .. e.value
end
out[#out+1] = '|}'
return table.concat(out, '\n')
end
function p.weapons(frame)
local key = arg1(frame)
local list = p._weapons(key)
if #list == 0 then
return "''No weapons deal this damage type in the current game data.''"
end
local out = { TBL, '|-',
TH .. 'Weapon', TH .. 'Class', TH .. 'Tier', TH .. key }
for _, e in ipairs(list) do
out[#out+1] = '|-'
out[#out+1] = '| ' .. Core.iconLink(e.rec, 24)
out[#out+1] = '| ' .. e.class
out[#out+1] = '| ' .. e.tier
out[#out+1] = '| data-sort-value="' .. tostring(e.sort) .. '" | ' .. e.value
end
out[#out+1] = '|}'
return table.concat(out, '\n')
end
return p