Module:GameSkills: Difference between revisions
From SpiritVale Wiki
More actions
No edit summary |
No edit summary |
||
| Line 94: | Line 94: | ||
end | end | ||
return table.concat(list, sep or ", ") | return table.concat(list, sep or ", ") | ||
end | |||
local function isNoneLike(v) | |||
if v == nil then return true end | |||
local s = mw.text.trim(tostring(v)) | |||
if s == "" then return true end | |||
s = mw.ustring.lower(s) | |||
return (s == "none" or s == "no" or s == "n/a" or s == "na" or s == "null") | |||
end | end | ||
| Line 190: | Line 198: | ||
end | end | ||
return true | return true | ||
end | |||
local function isZeroish(v) | |||
if v == nil then return true end | |||
if type(v) == "number" then return v == 0 end | |||
if type(v) == "table" and v.Value ~= nil then | |||
return isZeroish(v.Value) | |||
end | |||
local s = mw.text.trim(tostring(v)) | |||
if s == "" then return true end | |||
-- common “0” shapes once wikiprep has stringified | |||
if s == "0" or s == "0.0" or s == "0.00" then return true end | |||
if s == "0s" or s == "0 s" then return true end | |||
if s == "0m" or s == "0 m" then return true end | |||
if s == "0%" or s == "0 %" then return true end | |||
-- numeric-with-unit like "0.0000s" | |||
local n = tonumber((mw.ustring.gsub(s, "[^0-9%.%-]", ""))) | |||
return (n ~= nil and n == 0) | |||
end | end | ||
| Line 277: | Line 303: | ||
return baseText or perText | return baseText or perText | ||
end | |||
-- Prefer “value only” (dynSpan when series list exists) | |||
local function valuePairDynamicValueOnly(block, maxLevel, level) | |||
if type(block) ~= "table" then | |||
return nil | |||
end | |||
local base = block.Base | |||
local per = block["Per Level"] | |||
if type(per) == "table" then | |||
if #per == 0 then | |||
local baseText = formatUnitValue(base) | |||
return baseText and mw.text.nowiki(baseText) or nil | |||
end | |||
if isFlatList(per) then | |||
local one = formatUnitValue(per[1]) or tostring(per[1]) | |||
local show = formatUnitValue(base) or one | |||
return show and mw.text.nowiki(show) or nil | |||
end | |||
local series = {} | |||
for _, v in ipairs(per) do | |||
table.insert(series, formatUnitValue(v) or tostring(v)) | |||
end | |||
return dynSpan(series, level) | |||
end | |||
local txt = valuePairRawText(block) | |||
return txt and mw.text.nowiki(txt) or nil | |||
end | end | ||
| Line 337: | Line 395: | ||
return "Damage" | return "Damage" | ||
end | end | ||
| Line 466: | Line 466: | ||
end | end | ||
end | end | ||
end | end | ||
| Line 697: | Line 587: | ||
end | end | ||
local function formatStatusApplications(list, maxLevel, level) | local function formatStatusApplications(list, maxLevel, level, suppressDurationIndex) | ||
if type(list) ~= "table" or #list == 0 then | if type(list) ~= "table" or #list == 0 then | ||
return nil | return nil | ||
| Line 703: | Line 593: | ||
local parts = {} | local parts = {} | ||
for | for idx, s in ipairs(list) do | ||
if type(s) == "table" then | if type(s) == "table" then | ||
local typ = s.Type or s.Scope or "Target" | local typ = s.Type or s.Scope or "Target" | ||
| Line 711: | Line 601: | ||
local detail = {} | local detail = {} | ||
if type(s.Duration) == "table" then | -- Duration (optionally suppressed if Module 4 “promoted” it) | ||
if idx ~= suppressDurationIndex and type(s.Duration) == "table" then | |||
local t = valuePairDynamicText("Duration", s.Duration, maxLevel, level, "; ") | local t = valuePairDynamicText("Duration", s.Duration, maxLevel, level, "; ") | ||
if t then table.insert(detail, t) end | if t then table.insert(detail, t) end | ||
| Line 878: | Line 769: | ||
end | end | ||
local function buildEmptyModule(slot) | local function buildEmptyModule(slot) | ||
return moduleBox(slot, nil, "", true) | return moduleBox(slot, nil, "", true) | ||
| Line 885: | Line 775: | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
-- Module 1 – Level Selector | -- Module 1 – Level Selector | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
local function buildModuleLevelSelector(level, maxLevel) | local function buildModuleLevelSelector(level, maxLevel) | ||
| Line 910: | Line 799: | ||
:attr("aria-label", "Skill level select") | :attr("aria-label", "Skill level select") | ||
else | else | ||
inner:addClass("sv-level-ui-single") | inner:addClass("sv-level-ui-single") | ||
slider:addClass("sv-level-slider-single") | slider:addClass("sv-level-slider-single") | ||
| Line 920: | Line 808: | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
-- Module 2 – Skill Type | -- Module 2 – Skill Type | ||
-- (If non-damaging, hide Damage + Element; keep Target + Cast) | |||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
local function buildModuleSkillType(typeBlock) | local function buildModuleSkillType(typeBlock, hideDamageAndElement) | ||
typeBlock = (type(typeBlock) == "table") and typeBlock or {} | typeBlock = (type(typeBlock) == "table") and typeBlock or {} | ||
| Line 931: | Line 820: | ||
if x.Name and x.Name ~= "" then return tostring(x.Name) end | if x.Name and x.Name ~= "" then return tostring(x.Name) end | ||
if x.ID and x.ID ~= "" then return tostring(x.ID) end | if x.ID and x.ID ~= "" then return tostring(x.ID) end | ||
if x.Value ~= nil then return tostring(x.Value) end | |||
end | end | ||
if type(x) == "string" and x ~= "" then | if type(x) == "string" and x ~= "" then | ||
| Line 954: | Line 844: | ||
end | end | ||
addChunk("Damage", typeBlock.Damage or typeBlock["Damage Type"]) | if not hideDamageAndElement then | ||
addChunk("Damage", typeBlock.Damage or typeBlock["Damage Type"]) | |||
addChunk("Element", typeBlock.Element or typeBlock["Element Type"]) | |||
end | |||
addChunk("Target", typeBlock.Target or typeBlock["Target Type"]) | addChunk("Target", typeBlock.Target or typeBlock["Target Type"]) | ||
addChunk("Cast", typeBlock.Cast or typeBlock["Cast Type"]) | addChunk("Cast", typeBlock.Cast or typeBlock["Cast Type"]) | ||
| Line 965: | Line 858: | ||
-- ============================================================ | -- ============================================================ | ||
-- Module 3 – Skill Source (Modifier + Source + Scaling) | -- Module 3 – Skill Source (Modifier + Source + Scaling) | ||
-- | -- (unchanged from your current system) | ||
-- ============================================================ | -- ============================================================ | ||
| Line 1,016: | Line 904: | ||
end | end | ||
local function sourceValueForLevel(src, maxLevel, level) | local function sourceValueForLevel(src, maxLevel, level) | ||
if type(src) ~= "table" then | if type(src) ~= "table" then | ||
| Line 1,025: | Line 912: | ||
local per = src["Per Level"] | local per = src["Per Level"] | ||
if type(per) == "table" and #per > 0 then | if type(per) == "table" and #per > 0 then | ||
if isFlatList(per) then | if isFlatList(per) then | ||
| Line 1,040: | Line 926: | ||
end | end | ||
return valuePairDynamicValueOnly(src, maxLevel, level) | return valuePairDynamicValueOnly(src, maxLevel, level) | ||
end | end | ||
local function legacyPercentAtLevel(entry, level) | local function legacyPercentAtLevel(entry, level) | ||
if type(entry) ~= "table" then | if type(entry) ~= "table" then | ||
| Line 1,055: | Line 939: | ||
local perN = toNum(perRaw) | local perN = toNum(perRaw) | ||
if perN ~= nil and perN ~= 0 then | if perN ~= nil and perN ~= 0 then | ||
local total = (baseN or 0) + (perN * level) | local total = (baseN or 0) + (perN * level) | ||
| Line 1,077: | Line 960: | ||
local scaling = nil | local scaling = nil | ||
if type(rec.Source) == "table" then | if type(rec.Source) == "table" then | ||
local src = rec.Source | local src = rec.Source | ||
local atkFlag = (src["ATK-Based"] == true) | local atkFlag = (src["ATK-Based"] == true) | ||
local matkFlag = (src["MATK-Based"] == true) | local matkFlag = (src["MATK-Based"] == true) | ||
| Line 1,090: | Line 971: | ||
end | end | ||
if (sourceVal == nil or sourceVal == "") and type(rec.Damage) == "table" then | if (sourceVal == nil or sourceVal == "") and type(rec.Damage) == "table" then | ||
local dmg = rec.Damage | local dmg = rec.Damage | ||
| Line 1,099: | Line 979: | ||
local flat = dmg["Flat Damage"] | local flat = dmg["Flat Damage"] | ||
if type(main) == "table" and #main > 0 then | if type(main) == "table" and #main > 0 then | ||
local pick = nil | local pick = nil | ||
| Line 1,141: | Line 1,020: | ||
local hasScaling = (type(scalingLines) == "table" and #scalingLines > 0) | local hasScaling = (type(scalingLines) == "table" and #scalingLines > 0) | ||
if (not hasSource) and (not hasScaling) then | if (not hasSource) and (not hasScaling) then | ||
return nil | return nil | ||
| Line 1,148: | Line 1,026: | ||
local hasMod = (basisWord ~= nil and tostring(basisWord) ~= "") | local hasMod = (basisWord ~= nil and tostring(basisWord) ~= "") | ||
local extra = { "skill-source-module" } | local extra = { "skill-source-module" } | ||
table.insert(extra, hasMod and "sv-has-mod" or "sv-no-mod") | table.insert(extra, hasMod and "sv-has-mod" or "sv-no-mod") | ||
| Line 1,161: | Line 1,038: | ||
wrap:addClass("sv-source-grid") | wrap:addClass("sv-source-grid") | ||
if hasMod then | if hasMod then | ||
local modCol = wrap:tag("div"):addClass("sv-source-col"):addClass("sv-source-modifier") | local modCol = wrap:tag("div"):addClass("sv-source-col"):addClass("sv-source-modifier") | ||
modCol:tag("div") | modCol:tag("div"):addClass("sv-source-pill"):wikitext("Modifier") | ||
modCol:tag("div"):addClass("sv-modifier-value"):wikitext(mw.text.nowiki(basisWord)) | |||
modCol:tag("div") | |||
end | end | ||
if hasSource then | if hasSource then | ||
local sourceCol = wrap:tag("div"):addClass("sv-source-col"):addClass("sv-source-main") | local sourceCol = wrap:tag("div"):addClass("sv-source-col"):addClass("sv-source-main") | ||
sourceCol:tag("div") | sourceCol:tag("div"):addClass("sv-source-pill"):wikitext(mw.text.nowiki(sourceKind or "Source")) | ||
sourceCol:tag("div"):addClass("sv-source-value"):wikitext(sourceVal) | |||
sourceCol:tag("div") | |||
end | end | ||
if hasScaling then | if hasScaling then | ||
local scalingCol = wrap:tag("div"):addClass("sv-source-col"):addClass("sv-source-scaling") | local scalingCol = wrap:tag("div"):addClass("sv-source-col"):addClass("sv-source-scaling") | ||
scalingCol:tag("div") | scalingCol:tag("div"):addClass("sv-source-pill"):wikitext("Scaling") | ||
local list = scalingCol:tag("div"):addClass("sv-scaling-list") | local list = scalingCol:tag("div"):addClass("sv-scaling-list") | ||
for _, line in ipairs(scalingLines) do | for _, line in ipairs(scalingLines) do | ||
list:tag("div") | list:tag("div"):addClass("sv-scaling-item"):wikitext(mw.text.nowiki(line)) | ||
end | end | ||
end | end | ||
| Line 1,201: | Line 1,063: | ||
end | end | ||
-- ------------------------------------------------------------ | ---------------------------------------------------------------------- | ||
-- Module 4 – Quick Stats (3x2 | -- Module 4 – Quick Stats (3x2) | ||
-- Range / Area / Cost / Cast Time / Cooldown / Duration | -- Range / Area / Cost / Cast Time / Cooldown / Duration | ||
-- | -- - Zero values => — | ||
-- ------------------------------------------------------------ | -- - Area “none/missing” => — | ||
-- - Cost: HP only shows if non-zero at some level; never show "0 HP" | |||
-- - Special: if Duration missing AND skill is non-damaging, promote a status-application duration | |||
---------------------------------------------------------------------- | |||
local function seriesFromValuePair(block, maxLevel) | |||
return | if type(block) ~= "table" then | ||
return nil | |||
end | end | ||
local base = block.Base | |||
local function | local per = block["Per Level"] | ||
if type(v) == "table" and | |||
return | local function pickUnit(v) | ||
if type(v) == "table" and v.Unit and v.Unit ~= "" then | |||
return v.Unit | |||
end | end | ||
return nil | |||
end | |||
local unit = pickUnit(base) or pickUnit(per) | |||
local function fmtAny(v) | |||
local t = formatUnitValue(v) | local t = formatUnitValue(v) | ||
return t and mw.text.nowiki( | return t and tostring(t) or (v ~= nil and tostring(v) or nil) | ||
end | |||
local series = {} | |||
-- Preferred: expanded series (wikiprep) | |||
if type(per) == "table" and #per > 0 then | |||
for lv = 1, maxLevel do | |||
local raw = per[lv] or per[#per] | |||
local one = fmtAny(raw) | |||
if one == nil or isZeroish(raw) or isZeroish(one) then | |||
one = "—" | |||
end | |||
series[lv] = one | |||
end | |||
return series | |||
end | |||
-- Empty per-list -> base only | |||
if type(per) == "table" and #per == 0 then | |||
local one = fmtAny(base) | |||
if one == nil or isZeroish(base) or isZeroish(one) then | |||
one = "—" | |||
end | |||
for lv = 1, maxLevel do | |||
series[lv] = one | |||
end | |||
return series | |||
end | |||
-- Scalar per -> compute base + per*level (fallback) | |||
local baseN = toNum(base) or 0 | |||
local perN = toNum(per) | |||
if perN ~= nil then | |||
for lv = 1, maxLevel do | |||
local total = baseN + (perN * lv) | |||
local v = unit and { Value = total, Unit = unit } or total | |||
local one = fmtAny(v) | |||
if one == nil or total == 0 or isZeroish(one) then | |||
one = "—" | |||
end | |||
series[lv] = one | |||
end | |||
return series | |||
end | |||
-- Base-only scalar | |||
local raw = (base ~= nil) and base or per | |||
local one = fmtAny(raw) | |||
if one == nil then | |||
return nil | |||
end | |||
if isZeroish(raw) or isZeroish(one) then | |||
one = "—" | |||
end | |||
for lv = 1, maxLevel do | |||
series[lv] = one | |||
end | |||
return series | |||
end | |||
local function displayFromSeries(series, level) | |||
if type(series) ~= "table" or #series == 0 then | |||
return nil | |||
end | |||
local any = false | |||
for _, v in ipairs(series) do | |||
if v ~= "—" then | |||
any = true | |||
break | |||
end | |||
end | |||
if not any then | |||
return nil | |||
end | |||
if isFlatList(series) then | |||
return mw.text.nowiki(series[1]) | |||
end | |||
return dynSpan(series, level) | |||
end | |||
local function formatAreaSize(area) | |||
if type(area) ~= "table" then | |||
return nil | |||
end | end | ||
local | local raw = area["Area Size"] | ||
if type( | if raw == nil then | ||
return nil | |||
end | |||
local name, num | |||
if type(raw) == "table" then | |||
name = raw.Name or raw.ID or raw.Value | |||
num = raw.Value | |||
-- if name accidentally came from Value, prefer Name/ID if present | |||
if raw.Name or raw.ID then | |||
name = raw.Name or raw.ID | |||
end | end | ||
elseif type(raw) == "string" then | |||
if | name = raw | ||
elseif type(raw) == "number" then | |||
num = raw | |||
end | |||
-- fallback keys that sometimes exist depending on dict/wikiprep | |||
if num == nil then | |||
num = toNum(area["Area Value"]) or toNum(area["Area Size Value"]) or toNum(area["Area Number"]) or toNum(area["Area Radius"]) | |||
end | |||
if name ~= nil then | |||
local s = mw.text.trim(tostring(name)) | |||
if s == "" or isNoneLike(s) then | |||
return nil | return nil | ||
end | end | ||
if | -- if already contains "(...)" keep it | ||
if mw.ustring.find(s, "%(") then | |||
return mw.text.nowiki(s) | |||
end | end | ||
if num ~= nil and num ~= 0 then | |||
return mw.text.nowiki(string.format("%s (%s)", s, fmtNum(num))) | |||
end | end | ||
return mw.text.nowiki(s) | return mw.text.nowiki(s) | ||
end | end | ||
local function | if num ~= nil and num ~= 0 then | ||
local | return mw.text.nowiki(string.format("(%s)", fmtNum(num))) | ||
end | |||
return nil | |||
end | |||
local function skillHasAnyDamage(rec, maxLevel) | |||
-- “Has damage/source” for our UI decisions: | |||
-- - New Source with any non-zero at any level | |||
-- - OR legacy damage lists present | |||
if type(rec.Source) == "table" then | |||
local s = seriesFromValuePair(rec.Source, maxLevel) | |||
if s then | |||
for _, v in ipairs(s) do | |||
if v ~= "—" then return true end | |||
end | |||
end | |||
end | |||
if type(rec.Damage) == "table" then | |||
local dmg = rec.Damage | |||
for _, key in ipairs({ "Main Damage", "Flat Damage", "Reflect Damage" }) do | |||
local lst = dmg[key] | |||
if type(lst) == "table" and #lst > 0 then | |||
return true | |||
end | |||
end | |||
end | |||
return false | |||
end | |||
local function buildModuleQuickStats(rec, level, maxLevel, promo) | |||
local mech = (type(rec) == "table" and type(rec.Mechanics) == "table") and rec.Mechanics or {} | |||
local bt = (type(mech["Basic Timings"]) == "table") and mech["Basic Timings"] or {} | |||
local rc = (type(mech["Resource Cost"]) == "table") and mech["Resource Cost"] or {} | |||
local function dash() return "—" end | |||
-- Range (0 => —) | |||
local rangeVal = nil | |||
if mech.Range ~= nil and not isNoneLike(mech.Range) then | |||
local n = toNum(mech.Range) | |||
if n ~= nil then | |||
if n ~= 0 then | |||
rangeVal = mw.text.nowiki(formatUnitValue(mech.Range) or tostring(mech.Range)) | |||
end | |||
else | |||
-- non-numeric range (rare) – show unless “none” | |||
local t = mw.text.trim(tostring(mech.Range)) | |||
if t ~= "" and not isNoneLike(t) then | |||
rangeVal = mw.text.nowiki(t) | |||
end | |||
end | |||
end | |||
-- Area: Size (Number), none/missing => — | |||
local areaVal = formatAreaSize(mech.Area) | |||
-- Timings: 0 => — | |||
local castSeries = seriesFromValuePair(bt["Cast Time"], maxLevel) | |||
local cdSeries = seriesFromValuePair(bt["Cooldown"], maxLevel) | |||
local durSeries = seriesFromValuePair(bt["Duration"], maxLevel) | |||
if | -- Promote status duration if needed | ||
if (durSeries == nil) and type(promo) == "table" and type(promo.durationBlock) == "table" then | |||
durSeries = seriesFromValuePair(promo.durationBlock, maxLevel) | |||
end | |||
local castVal = displayFromSeries(castSeries, level) | |||
local cdVal = displayFromSeries(cdSeries, level) | |||
local durVal = displayFromSeries(durSeries, level) | |||
-- Cost: build combined series, and never show "0 HP" | |||
local function labeledSeries(block, label) | |||
local s = seriesFromValuePair(block, maxLevel) | |||
if not s then return nil end | |||
local any = false | |||
for i, v in ipairs(s) do | |||
if v ~= "—" then | |||
s[i] = tostring(v) .. " " .. label | |||
any = true | |||
else | |||
s[i] = "—" | |||
end | |||
end | end | ||
return | return any and s or nil | ||
end | end | ||
local | local mpS = labeledSeries(rc["Mana Cost"], "MP") | ||
local | local hpS = labeledSeries(rc["Health Cost"], "HP") | ||
local | |||
local costSeries = {} | |||
for lv = 1, maxLevel do | |||
local mp = mpS and mpS[lv] or "—" | |||
local hp = hpS and hpS[lv] or "—" | |||
if mp ~= "—" and hp ~= "—" then | |||
costSeries[lv] = mp .. " + " .. hp | |||
local | elseif mp ~= "—" then | ||
costSeries[lv] = mp | |||
elseif hp ~= "—" then | |||
costSeries[lv] = hp | |||
else | |||
costSeries[lv] = "—" | |||
end | |||
end | |||
local costVal = displayFromSeries(costSeries, level) | |||
local grid = mw.html.create("div") | local grid = mw.html.create("div") | ||
| Line 1,282: | Line 1,347: | ||
return moduleBox(4, "module-quick-stats", tostring(grid), false) | return moduleBox(4, "module-quick-stats", tostring(grid), false) | ||
end | |||
local function computeDurationPromotion(rec, maxLevel) | |||
-- Only: | |||
-- - non-damaging skills | |||
-- - AND missing/blank Duration in Basic Timings | |||
-- - AND a Status Application has a Duration block | |||
-- Then: promote that status duration into Module 4 and suppress it in Applies row. | |||
if type(rec) ~= "table" then return nil end | |||
if skillHasAnyDamage(rec, maxLevel) then return nil end | |||
local mech = (type(rec.Mechanics) == "table") and rec.Mechanics or {} | |||
local bt = (type(mech["Basic Timings"]) == "table") and mech["Basic Timings"] or {} | |||
local durS = seriesFromValuePair(bt["Duration"], maxLevel) | |||
if durS ~= nil then | |||
-- Duration exists (even if some entries are —), so we don’t promote. | |||
return nil | |||
end | |||
local apps = rec["Status Applications"] | |||
if type(apps) ~= "table" then return nil end | |||
for idx, app in ipairs(apps) do | |||
if type(app) == "table" and type(app.Duration) == "table" then | |||
local s = seriesFromValuePair(app.Duration, maxLevel) | |||
if s then | |||
for _, v in ipairs(s) do | |||
if v ~= "—" then | |||
return { | |||
durationBlock = app.Duration, | |||
suppressDurationIndex = idx, | |||
} | |||
end | |||
end | |||
end | |||
end | |||
end | |||
return nil | |||
end | end | ||
| Line 1,287: | Line 1,392: | ||
local grid = mw.html.create("div") | local grid = mw.html.create("div") | ||
grid:addClass("hero-modules-grid") | grid:addClass("hero-modules-grid") | ||
local nonDamaging = false | |||
do | |||
local dmgVal = nil | |||
if type(rec.Type) == "table" then | |||
dmgVal = rec.Type.Damage or rec.Type["Damage Type"] | |||
if type(dmgVal) == "table" then | |||
dmgVal = dmgVal.Name or dmgVal.ID or dmgVal.Value | |||
end | |||
end | |||
nonDamaging = isNoneLike(dmgVal) or (not skillHasAnyDamage(rec, maxLevel)) | |||
end | |||
local promo = computeDurationPromotion(rec, maxLevel) | |||
grid:wikitext(buildModuleLevelSelector(level, maxLevel)) | grid:wikitext(buildModuleLevelSelector(level, maxLevel)) | ||
grid:wikitext(buildModuleSkillType(rec.Type or {})) | grid:wikitext(buildModuleSkillType(rec.Type or {}, nonDamaging)) | ||
local m3 = buildModuleSkillSource(rec, level, maxLevel) | local m3 = buildModuleSkillSource(rec, level, maxLevel) | ||
grid:wikitext(m3 or buildEmptyModule(3)) | grid:wikitext(m3 or buildEmptyModule(3)) | ||
grid:wikitext(buildModuleQuickStats(rec, level, maxLevel, promo)) | |||
grid:wikitext(buildModuleQuickStats(rec, level, maxLevel)) | |||
return tostring(grid) | return tostring(grid), promo | ||
end | end | ||
| Line 1,383: | Line 1,501: | ||
end | end | ||
local modulesUI, promo = buildHeroModulesUI(rec, level, maxLevel) | |||
addHeroModulesRow(root, modulesUI) | |||
if showUsers then | if showUsers then | ||
| Line 1,420: | Line 1,539: | ||
local mech = rec.Mechanics or {} | local mech = rec.Mechanics or {} | ||
if next(mech) ~= nil then | if next(mech) ~= nil then | ||
-- | -- Range / Area / Timing / Resource Cost rows are removed: | ||
-- | -- They’re now covered by Module 4. | ||
if mech["Autocast Multiplier"] ~= nil then | if mech["Autocast Multiplier"] ~= nil then | ||
addRow(root, "Autocast Multiplier", tostring(mech["Autocast Multiplier"]), "sv-row-mech", "Mechanics.Autocast Multiplier") | addRow(root, "Autocast Multiplier", tostring(mech["Autocast Multiplier"]), "sv-row-mech", "Mechanics.Autocast Multiplier") | ||
| Line 1,464: | Line 1,582: | ||
end | end | ||
local statusApps = formatStatusApplications(rec["Status Applications"], maxLevel, level) | local suppressIdx = (type(promo) == "table") and promo.suppressDurationIndex or nil | ||
local statusApps = formatStatusApplications(rec["Status Applications"], maxLevel, level, suppressIdx) | |||
local statusRem = formatStatusRemoval(rec["Status Removal"], maxLevel, level) | local statusRem = formatStatusRemoval(rec["Status Removal"], maxLevel, level) | ||
if statusApps or statusRem then | if statusApps or statusRem then | ||