Module:GameSkills: Difference between revisions
From SpiritVale Wiki
More actions
No edit summary |
No edit summary |
||
| Line 4: | Line 4: | ||
-- - Adds a per-skill Level Select slider (client-side JS updates fields) | -- - Adds a per-skill Level Select slider (client-side JS updates fields) | ||
-- - Default level = Max Level | -- - Default level = Max Level | ||
-- - Adds .sv-skill-card + data-max-level/data-level hooks for JS | -- - Adds .sv-skill-card + data-max-level / data-level hooks for JS | ||
-- - Replaces large Lv1/Lv2/... lists with data-series dynamic spans | -- - Replaces large Lv1/Lv2/... lists with data-series dynamic spans | ||
-- | -- | ||
| Line 170: | Line 170: | ||
-- Like your old valuePairLines/valuePairText, but: | -- Like your old valuePairLines/valuePairText, but: | ||
-- - if Per Level is a list, | -- - if Per Level is a list, render a dynamic span instead of "v1 / v2 / ..." | ||
-- - scalar Per Level stays as the old "Base" | -- - scalar Per Level stays as the old "Base" + "Per Level" lines (still short) | ||
local function valuePairDynamicLines(name, block, maxLevel, level) | local function valuePairDynamicLines(name, block, maxLevel, level) | ||
if type(block) ~= "table" then | if type(block) ~= "table" then | ||
| Line 191: | Line 191: | ||
end | end | ||
-- | -- flat list -> show single value | ||
if isFlatList(per) then | if isFlatList(per) then | ||
local baseText = formatUnitValue(base) | local baseText = formatUnitValue(base) | ||
| Line 202: | Line 202: | ||
end | end | ||
-- | -- dynamic series | ||
local series = {} | local series = {} | ||
for _, v in ipairs(per) do | for _, v in ipairs(per) do | ||
| Line 215: | Line 215: | ||
end | end | ||
-- | -- scalar Per Level (keep old style) | ||
local lines = {} | local lines = {} | ||
local baseText = formatUnitValue(base) | local baseText = formatUnitValue(base) | ||
| Line 326: | Line 326: | ||
-- No scaling -> just show base | -- No scaling -> just show base | ||
if perN == nil or perN == 0 or not maxLevel or maxLevel <= 0 then | if perN == nil or perN == 0 or not maxLevel or maxLevel <= 0 then | ||
return baseText and | return baseText and mw.text.nowiki(baseText .. " " .. basis) or nil | ||
end | end | ||
| Line 543: | Line 543: | ||
end | end | ||
local function formatMechanicEffects(effects) | -- UPDATED: Special Mechanics now supports dynamic Per Level lists | ||
local function formatMechanicEffects(effects, maxLevel, level) | |||
if type(effects) ~= "table" then | if type(effects) ~= "table" then | ||
return nil | return nil | ||
| Line 555: | Line 556: | ||
local parts = {} | local parts = {} | ||
-- Helper: returns a dynamic amount when Per Level is a list | |||
local function effectAmount(block) | |||
if type(block) ~= "table" then | |||
return nil | |||
end | |||
local per = block["Per Level"] | |||
-- If Per Level is a list, show a dynamic span unless it's flat (no scaling) | |||
if type(per) == "table" and #per > 0 then | |||
if isFlatList(per) then | |||
return mw.text.nowiki(formatUnitValue(per[1]) or tostring(per[1])) | |||
end | |||
local series = {} | |||
for _, v in ipairs(per) do | |||
table.insert(series, formatUnitValue(v) or tostring(v)) | |||
end | |||
return dynSpan(series, level) | |||
end | |||
-- Fallback: old raw text (scalar Base/Per Level) | |||
local pair = { Base = block.Base, ["Per Level"] = block["Per Level"] } | |||
local txt = valuePairRawText(pair) | |||
return txt and mw.text.nowiki(txt) or nil | |||
end | |||
for _, name in ipairs(keys) do | for _, name in ipairs(keys) do | ||
local block = effects[name] | local block = effects[name] | ||
if type(block) == "table" then | if type(block) == "table" then | ||
local t = block.Type | local t = block.Type | ||
-- If effect has a Type, keep "Type - Name + Amount" | |||
if t ~= nil and tostring(t) ~= "" then | if t ~= nil and tostring(t) ~= "" then | ||
local | local amt = effectAmount(block) | ||
local | local seg = mw.text.nowiki(tostring(t) .. " - " .. tostring(name)) | ||
if amt then | if amt then | ||
seg = seg .. " + " .. amt | |||
end | end | ||
table.insert(parts, seg) | |||
-- Otherwise render like "Chains: <dynamic>" | |||
else | else | ||
local txt = valuePairDynamicText(name, block, maxLevel, level, ", ") | |||
local txt = | |||
if txt then | if txt then | ||
table.insert(parts, | table.insert(parts, txt) | ||
end | end | ||
end | end | ||
| Line 786: | Line 816: | ||
local function buildLevelSelectUI(level, maxLevel) | local function buildLevelSelectUI(level, maxLevel) | ||
-- Matches | -- Matches JS expectations: | ||
-- .sv-level-slider placeholder for the <input type="range"> | -- .sv-level-slider placeholder for the <input type="range"> | ||
-- .sv-level-num span for updating the number | -- .sv-level-num span for updating the number | ||
| Line 806: | Line 836: | ||
if maxLevel < 1 then maxLevel = 1 end | if maxLevel < 1 then maxLevel = 1 end | ||
-- Always default to max level | -- Always default to max level | ||
local | local level = clamp(maxLevel, 1, maxLevel) | ||
local root = mw.html.create("table") | local root = mw.html.create("table") | ||
| Line 818: | Line 847: | ||
root:attr("data-level", tostring(level)) | root:attr("data-level", tostring(level)) | ||
-- Top "hero" row | |||
-- Top "hero" row | |||
local icon = rec.Icon | local icon = rec.Icon | ||
local title = rec["External Name"] or rec.Name or rec["Internal Name"] or "Unknown Skill" | local title = rec["External Name"] or rec.Name or rec["Internal Name"] or "Unknown Skill" | ||
| Line 854: | Line 881: | ||
end | end | ||
-- General | -- General | ||
addSectionHeader(root, "General") | addSectionHeader(root, "General") | ||
addRow(root, "Level Select", buildLevelSelectUI(level, maxLevel)) | addRow(root, "Level Select", buildLevelSelectUI(level, maxLevel)) | ||
if showUsers then | if showUsers then | ||
local users = rec.Users or {} | local users = rec.Users or {} | ||
| Line 873: | Line 893: | ||
end | end | ||
-- Requirements | -- Requirements | ||
local req = rec.Requirements or {} | local req = rec.Requirements or {} | ||
if (req["Required Skills"] and #req["Required Skills"] > 0) | if (req["Required Skills"] and #req["Required Skills"] > 0) | ||
| Line 886: | Line 904: | ||
local skillParts = {} | local skillParts = {} | ||
for _, rs in ipairs(req["Required Skills"]) do | for _, rs in ipairs(req["Required Skills"]) do | ||
local nameReq | local nameReq = rs["Skill External Name"] or rs["Skill Internal Name"] or "Unknown" | ||
local lvlReq = rs["Required Level"] | local lvlReq = rs["Required Level"] | ||
if lvlReq then | if lvlReq then | ||
table.insert(skillParts, string.format("%s (Lv.%s)", nameReq, lvlReq)) | table.insert(skillParts, string.format("%s (Lv.%s)", nameReq, lvlReq)) | ||
| Line 901: | Line 919: | ||
end | end | ||
-- Type | -- Type | ||
local typeBlock = rec.Type or {} | local typeBlock = rec.Type or {} | ||
if next(typeBlock) ~= nil then | if next(typeBlock) ~= nil then | ||
| Line 929: | Line 945: | ||
end | end | ||
-- Mechanics | -- Mechanics | ||
local mech = rec.Mechanics or {} | local mech = rec.Mechanics or {} | ||
if next(mech) ~= nil then | if next(mech) ~= nil then | ||
addSectionHeader(root, "Mechanics") | addSectionHeader(root, "Mechanics") | ||
addRow(root, "Range", formatUnitValue(mech.Range)) | |||
addRow(root, "Range", | |||
addRow(root, "Area", formatArea(mech.Area, maxLevel, level)) | |||
if mech["Autocast Multiplier"] ~= nil then | if mech["Autocast Multiplier"] ~= nil then | ||
| Line 946: | Line 958: | ||
end | end | ||
addRow(root, "Timing", formatTimingBlock(mech["Basic Timings"], maxLevel, level)) | |||
addRow(root, "Resource Cost", formatResourceCost(mech["Resource Cost"], maxLevel, level)) | |||
addRow(root, "Combo", formatCombo(mech.Combo)) | |||
addRow(root, "Combo", | |||
-- UPDATED CALL: pass maxLevel + level | |||
addRow(root, "Special Mechanics", | addRow(root, "Special Mechanics", formatMechanicEffects(mech.Effects, maxLevel, level)) | ||
end | end | ||
-- Damage & Scaling | -- Damage & Scaling | ||
local dmg = rec.Damage or {} | local dmg = rec.Damage or {} | ||
if next(dmg) ~= nil then | if next(dmg) ~= nil then | ||
addSectionHeader(root, "Damage and Scaling") | addSectionHeader(root, "Damage and Scaling") | ||
local main = dmg["Main Damage"] | local main = dmg["Main Damage"] | ||
local mainNonHeal = {} | local mainNonHeal, healOnly = {}, {} | ||
if type(main) == "table" then | if type(main) == "table" then | ||
| Line 987: | Line 992: | ||
local reflHas = (type(reflList) == "table" and #reflList > 0) | local reflHas = (type(reflList) == "table" and #reflList > 0) | ||
local pureHealing = (#healOnly > 0) and (#mainNonHeal == 0) and (not flatHas) and (not reflHas) | local pureHealing = (#healOnly > 0) and (#mainNonHeal == 0) and (not flatHas) and (not reflHas) | ||
addRow(root, "Main Damage", formatDamageList(mainNonHeal, maxLevel, level, (#mainNonHeal > 1))) | |||
addRow(root, " | addRow(root, "Flat Damage", formatDamageList(flatList, maxLevel, level, false)) | ||
addRow(root, "Reflect Damage", formatDamageList(reflList, maxLevel, level, false)) | |||
addRow(root, "Healing", formatDamageList(healOnly, maxLevel, level, false)) | |||
addRow(root, "Scaling", formatScaling(dmg.Scaling, pureHealing and "Healing" or nil)) | |||
addRow(root, " | |||
end | end | ||
-- Modifiers | -- Modifiers | ||
local modsText = formatModifiers(rec.Modifiers) | local modsText = formatModifiers(rec.Modifiers) | ||
if modsText then | if modsText then | ||
| Line 1,015: | Line 1,009: | ||
end | end | ||
-- Status | -- Status | ||
local statusApps = formatStatusApplications(rec["Status Applications"], maxLevel, level) | local statusApps = formatStatusApplications(rec["Status Applications"], maxLevel, level) | ||
local statusRem = formatStatusRemoval(rec["Status Removal"], maxLevel, level) | local statusRem = formatStatusRemoval(rec["Status Removal"], maxLevel, level) | ||
| Line 1,026: | Line 1,018: | ||
end | end | ||
-- Events | -- Events | ||
local eventsText = formatEvents(rec.Events) | local eventsText = formatEvents(rec.Events) | ||
if eventsText then | if eventsText then | ||
| Line 1,035: | Line 1,025: | ||
end | end | ||
-- Notes | -- Notes | ||
if type(rec.Notes) == "table" and #rec.Notes > 0 then | if type(rec.Notes) == "table" and #rec.Notes > 0 then | ||
addSectionHeader(root, "Notes") | addSectionHeader(root, "Notes") | ||
| Line 1,100: | Line 1,088: | ||
local rec | local rec | ||
if name and name ~= "" then | if name and name ~= "" then | ||
rec = findSkillByName(name) | rec = findSkillByName(name) | ||