Module:GameSkills: Difference between revisions
From SpiritVale Wiki
More actions
No edit summary |
No edit summary |
||
| Line 145: | Line 145: | ||
return (v ~= nil) and tostring(v) or nil | return (v ~= nil) and tostring(v) or nil | ||
end | |||
-- svgInfoIcon: render a small inline info icon (circle + “i”). | |||
local function svgInfoIcon(size) | |||
size = tonumber(size) or 16 | |||
return string.format( | |||
'<svg class="sv-ico sv-ico--info" width="%d" height="%d" viewBox="0 0 16 16" aria-hidden="true" focusable="false">' .. | |||
'<circle cx="8" cy="8" r="7" fill="var(--sv-ico-bg, #6aa6ff)"></circle>' .. | |||
'<path d="M8 4.25a1 1 0 1 0 0 2a1 1 0 0 0 0-2zm1 8.5H7V6.5h2v6.25z" fill="var(--sv-ico-fg, #081018)"></path>' .. | |||
'</svg>', | |||
size, size | |||
) | |||
end | end | ||
| Line 875: | Line 887: | ||
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" | ||
local notesList = {} | |||
if type(rec.Notes) == "table" then | |||
for _, note in ipairs(rec.Notes) do | |||
local n = trim(note) | |||
if n then | |||
table.insert(notesList, mw.text.nowiki(n)) | |||
end | |||
end | |||
elseif type(rec.Notes) == "string" then | |||
local n = trim(rec.Notes) | |||
if n then | |||
notesList = { mw.text.nowiki(n) } | |||
end | |||
end | |||
local req = rec.Requirements or {} | |||
local reqSkills = (type(req["Required Skills"]) == "table") and req["Required Skills"] or {} | |||
local reqWeapons = (type(req["Required Weapons"]) == "table") and req["Required Weapons"] or {} | |||
local reqStances = (type(req["Required Stances"]) == "table") and req["Required Stances"] or {} | |||
local hasNotes = (#notesList > 0) | |||
local hasReq = (#reqSkills > 0) or (#reqWeapons > 0) or (#reqStances > 0) | |||
local wrap = mw.html.create("div") | local wrap = mw.html.create("div") | ||
wrap:addClass("sv-herobar-1-wrap") | wrap:addClass("sv-herobar-1-wrap") | ||
wrap:addClass("sv-tip-scope") | |||
local iconBox = wrap:tag("div") | |||
iconBox:addClass("sv-herobar-icon") | |||
local metaBox = wrap:tag("div") | |||
metaBox:addClass("sv-herobar-meta") | |||
if icon and icon ~= "" then | if icon and icon ~= "" then | ||
iconBox:wikitext(string.format("[[File:%s|80px|link=]]", icon)) | |||
end | |||
if hasNotes then | |||
local notesBtn = mw.html.create("button") | |||
notesBtn:addClass("sv-tip-btn sv-tip-btn--notes") | |||
notesBtn:attr("type", "button") | |||
notesBtn:attr("data-sv-tip", "notes") | |||
notesBtn:attr("aria-label", "Notes") | |||
notesBtn:attr("aria-expanded", "false") | |||
notesBtn:wikitext(svgInfoIcon(16)) | |||
iconBox:node(notesBtn) | |||
end | end | ||
metaBox:tag("div") | |||
:addClass("spiritvale-infobox-title") | :addClass("spiritvale-infobox-title") | ||
:wikitext(title) | :wikitext(title) | ||
if hasReq then | |||
local pillRow = metaBox:tag("div") | |||
pillRow:addClass("sv-pill-row") | |||
local pill = mw.html.create("button") | |||
end | pill:addClass("sv-pill sv-pill--req sv-tip-btn") | ||
pill:attr("type", "button") | |||
pill:attr("data-sv-tip", "req") | |||
pill:attr("aria-label", "Requirements") | |||
pill:attr("aria-expanded", "false") | |||
pill:wikitext("Requirements") | |||
pillRow:node(pill) | |||
end | |||
if hasNotes then | |||
local notesContent = wrap:tag("div") | |||
notesContent:addClass("sv-tip-content") | |||
notesContent:attr("data-sv-tip-content", "notes") | |||
notesContent:tag("div"):addClass("sv-tip-title"):wikitext("Notes") | |||
notesContent:tag("div"):wikitext(table.concat(notesList, "<br />")) | |||
end | |||
if hasReq then | |||
local reqContent = wrap:tag("div") | |||
reqContent:addClass("sv-tip-content") | |||
reqContent:attr("data-sv-tip-content", "req") | |||
reqContent:tag("div"):addClass("sv-tip-title"):wikitext("Requirements") | |||
-- PLUGIN: SkillType (Hero Bar Slot 2) - 2 rows x 3 cells (desktop + mobile). | if #reqSkills > 0 then | ||
-- Rules: | local skillLines = {} | ||
-- - If skill is non-damaging, hide Damage/Element/Hits. | for _, rs in ipairs(reqSkills) do | ||
-- - If Hits is empty, hide Hits. | if type(rs) == "table" then | ||
-- - If Combo is empty, hide Combo. | local nameReq = rs["Skill External Name"] or rs["Skill Internal Name"] or "Unknown" | ||
local lvlReq = rs["Required Level"] | |||
if lvlReq then | |||
table.insert(skillLines, string.format("%s (Lv.%s)", mw.text.nowiki(nameReq), mw.text.nowiki(tostring(lvlReq)))) | |||
else | |||
table.insert(skillLines, mw.text.nowiki(nameReq)) | |||
end | |||
end | |||
end | |||
if #skillLines > 0 then | |||
local section = reqContent:tag("div") | |||
section:addClass("sv-tip-section") | |||
section:tag("span"):addClass("sv-tip-label"):wikitext("Required Skills") | |||
section:tag("div"):wikitext(table.concat(skillLines, "<br />")) | |||
end | |||
end | |||
if #reqWeapons > 0 then | |||
local weapons = {} | |||
for _, w in ipairs(reqWeapons) do | |||
local wn = trim(w) | |||
if wn then table.insert(weapons, mw.text.nowiki(wn)) end | |||
end | |||
if #weapons > 0 then | |||
local section = reqContent:tag("div") | |||
section:addClass("sv-tip-section") | |||
section:tag("span"):addClass("sv-tip-label"):wikitext("Required Weapons") | |||
section:tag("div"):wikitext(table.concat(weapons, ", ")) | |||
end | |||
end | |||
if #reqStances > 0 then | |||
local stances = {} | |||
for _, s in ipairs(reqStances) do | |||
local sn = trim(s) | |||
if sn then table.insert(stances, mw.text.nowiki(sn)) end | |||
end | |||
if #stances > 0 then | |||
local section = reqContent:tag("div") | |||
section:addClass("sv-tip-section") | |||
section:tag("span"):addClass("sv-tip-label"):wikitext("Required Stances") | |||
section:tag("div"):wikitext(table.concat(stances, ", ")) | |||
end | |||
end | |||
end | |||
return { | |||
inner = tostring(wrap), | |||
classes = "module-icon-name", | |||
} | |||
end | |||
-- PLUGIN: SkillType (Hero Bar Slot 2) - 2 rows x 3 cells (desktop + mobile). | |||
-- Rules: | |||
-- - If skill is non-damaging, hide Damage/Element/Hits. | |||
-- - If Hits is empty, hide Hits. | |||
-- - If Combo is empty, hide Combo. | |||
-- Ordering: | -- Ordering: | ||
-- - Desktop: Damage, Element, Hits, Target, Cast, Combo | -- - Desktop: Damage, Element, Hits, Target, Cast, Combo | ||
| Line 1,742: | Line 1,870: | ||
end | end | ||
-- Mechanics (keep small extras only) | |||
local mech = rec.Mechanics or {} | |||
if next(mech) ~= nil then | |||
if mech["Autocast Multiplier"] ~= nil then | |||
addRow(root, "Autocast Multiplier", tostring(mech["Autocast Multiplier"]), "sv-row-mech", "Mechanics.Autocast Multiplier") | |||
end | |||
end | |||
-- Legacy damage breakdown (only when Source absent) | -- Legacy damage breakdown (only when Source absent) | ||
| Line 1,891: | Line 1,993: | ||
end | end | ||
return tostring(root) | |||
end | end | ||