Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Join the Playtest on Steam Now: SpiritVale

Module:GameSkills: Difference between revisions

From SpiritVale Wiki
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, we render a dynamic span instead of "v1 / v2 / ...".
-- - if Per Level is a list, render a dynamic span instead of "v1 / v2 / ..."
-- - scalar Per Level stays as the old "Base" and "Per Level" lines (still short).
-- - 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
-- 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
-- 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)
-- 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 (mw.text.nowiki(baseText .. " " .. basis)) or nil
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 pair = { Base = block.Base, ["Per Level"] = block["Per Level"] }
local amt = effectAmount(block)
local amt = valuePairRawText(pair)
local seg = mw.text.nowiki(tostring(t) .. " - " .. tostring(name))
if amt then
if amt then
table.insert(parts, string.format("%s - %s + %s", tostring(t), tostring(name), amt))
seg = seg .. " + " .. amt
else
table.insert(parts, string.format("%s - %s", tostring(t), tostring(name)))
end
end
table.insert(parts, seg)
-- Otherwise render like "Chains: <dynamic>"
else
else
-- Keep old behavior here (usually not huge)
local txt = valuePairDynamicText(name, block, maxLevel, level, ", ")
local txt = valuePairRawText(block)
if txt then
if txt then
table.insert(parts, mw.text.nowiki(tostring(name) .. ": " .. txt))
table.insert(parts, txt)
end
end
end
end
Line 786: Line 816:


local function buildLevelSelectUI(level, maxLevel)
local function buildLevelSelectUI(level, maxLevel)
-- Matches the JS expectations:
-- 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 (your requirement)
-- Always default to max level
local level = maxLevel
local level = clamp(maxLevel, 1, maxLevel)
level = clamp(level, 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: icon + name (left), description (right)
-- ==========================================================
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")
-- Replace Max Level -> Level Select (slider)
addRow(root, "Level Select", buildLevelSelectUI(level, maxLevel))
addRow(root, "Level Select", buildLevelSelectUI(level, maxLevel))


-- Hide Users on:
--  - list pages (opts.showUsers=false)
--  - the skill's own page (handled by caller)
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 = rs["Skill External Name"] or rs["Skill Internal Name"] or "Unknown"
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")


local rangeText = formatUnitValue(mech.Range)
addRow(root, "Range", formatUnitValue(mech.Range))
addRow(root, "Range", rangeText)


local areaText = formatArea(mech.Area, maxLevel, level)
addRow(root, "Area", formatArea(mech.Area, maxLevel, level))
addRow(root, "Area", areaText)


if mech["Autocast Multiplier"] ~= nil then
if mech["Autocast Multiplier"] ~= nil then
Line 946: Line 958:
end
end


local btText = formatTimingBlock(mech["Basic Timings"], maxLevel, level)
addRow(root, "Timing", formatTimingBlock(mech["Basic Timings"], maxLevel, level))
addRow(root, "Timing", btText)


local rcText = formatResourceCost(mech["Resource Cost"], maxLevel, level)
addRow(root, "Resource Cost", formatResourceCost(mech["Resource Cost"], maxLevel, level))
addRow(root, "Resource Cost", rcText)


local comboText = formatCombo(mech.Combo)
addRow(root, "Combo", formatCombo(mech.Combo))
addRow(root, "Combo", comboText)


local effText = formatMechanicEffects(mech.Effects)
-- UPDATED CALL: pass maxLevel + level
addRow(root, "Special Mechanics", effText)
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")


-- Split healing out of Main Damage (Type == "Healing")
local main = dmg["Main Damage"]
local main = dmg["Main Damage"]
local mainNonHeal = {}
local mainNonHeal, healOnly = {}, {}
local 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)


-- Determine if this is effectively a "pure healing" skill for scaling wording.
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)


local mainText = formatDamageList(mainNonHeal, maxLevel, level, (#mainNonHeal > 1))
addRow(root, "Main Damage", formatDamageList(mainNonHeal, maxLevel, level, (#mainNonHeal > 1)))
addRow(root, "Main Damage", mainText)
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))


local flatText = formatDamageList(flatList, maxLevel, level, false)
addRow(root, "Scaling", formatScaling(dmg.Scaling, pureHealing and "Healing" or nil))
addRow(root, "Flat Damage", flatText)
 
local reflText = formatDamageList(reflList, maxLevel, level, false)
addRow(root, "Reflect Damage", reflText)
 
local healText = formatDamageList(healOnly, maxLevel, level, false)
addRow(root, "Healing", healText)
 
local scaleText = formatScaling(dmg.Scaling, pureHealing and "Healing" or nil)
addRow(root, "Scaling", scaleText)
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)