Module:GameSkills: Difference between revisions
From SpiritVale Wiki
More actions
m Protected "Module:GameSkills" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) [cascading] |
No edit summary |
||
| (4 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- Module:GameSkills | -- Module:GameSkills | ||
-- | -- | ||
-- Renders skill data (from Data:skills.json) into an infobox | -- Renders active skill data (from Data:skills.json) into an infobox-style table | ||
-- | -- and can also list all skills for a given user/class. | ||
-- | -- | ||
-- | -- Usage (single skill): | ||
-- {{Skill| | -- {{Skill|Heal}} | ||
-- {{Skill|name= | -- {{Skill|name=Heal}} | ||
-- {{Skill|id= | -- {{Skill|id=Heal_InternalId}} | ||
-- | |||
-- Usage (auto-list on class page, e.g. "Acolyte"): | |||
-- {{Skill}} -> lists all Acolyte skills (page name) | |||
-- {{Skill|Acolyte}} -> same, if no skill literally called "Acolyte" | |||
local GameData = require("Module:GameData") | local GameData = require("Module:GameData") | ||
| Line 27: | Line 31: | ||
local function getArgs(frame) | local function getArgs(frame) | ||
local parent = frame:getParent() | local parent = frame:getParent() | ||
if parent then | if parent then | ||
| Line 35: | Line 38: | ||
end | end | ||
local function listToText(list) | local function listToText(list, sep) | ||
if type(list) ~= "table" or #list == 0 then | if type(list) ~= "table" or #list == 0 then | ||
return nil | return nil | ||
end | end | ||
return table.concat(list, ", ") | return table.concat(list, sep or ", ") | ||
end | end | ||
| Line 51: | Line 54: | ||
end | end | ||
local function | local function addSectionHeader(tbl, label) | ||
local row = tbl:tag("tr") | |||
local cell = row:tag("th") | |||
cell:attr("colspan", 2) | |||
cell:addClass("spiritvale-infobox-section-header") | |||
cell:wikitext(label) | |||
end | |||
-- Lookup by Internal Name | |||
local function getSkillById(id) | |||
if not id or id == "" then | |||
return nil | return nil | ||
end | end | ||
local | local dataset = getSkills() | ||
local | local byId = dataset.byId or {} | ||
return byId[id] | |||
end | |||
-- Lookup by display Name (for editors) | |||
local function findSkillByName(name) | |||
if not name or name == "" then | |||
return nil | return nil | ||
end | end | ||
local dataset = getSkills() | |||
for _, rec in ipairs(dataset.records or {}) do | |||
if rec["Name"] == name then | |||
return rec | |||
end | |||
end | |||
return nil | |||
end | end | ||
local function | ---------------------------------------------------------------------- | ||
-- Formatting helpers | |||
---------------------------------------------------------------------- | |||
local function formatBasePer(block) | |||
if type(block) ~= "table" then | if type(block) ~= "table" then | ||
return nil | return nil | ||
end | end | ||
local parts = {} | |||
if block.Base ~= nil then | |||
table.insert(parts, string.format("Base %s", tostring(block.Base))) | |||
end | |||
if block["Per Level"] ~= nil then | |||
table.insert(parts, string.format("%s / Lv", tostring(block["Per Level"]))) | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, ", ") | |||
end | |||
local base = | local function formatMainDamage(list) | ||
if type(list) ~= "table" or #list == 0 then | |||
return nil | |||
end | |||
local parts = {} | |||
for _, d in ipairs(list) do | |||
if type(d) == "table" then | |||
local kind = d.Type or "Damage" | |||
local base = d["Base %"] | |||
local per = d["Per Level %"] | |||
local seg = kind | |||
local detail = {} | |||
if base ~= nil then | |||
table.insert(detail, string.format("Base %s%%", tostring(base))) | |||
end | |||
if per ~= nil then | |||
table.insert(detail, string.format("%s%% / Lv", tostring(per))) | |||
end | |||
if d["ATK-Based"] then | |||
table.insert(detail, "ATK-based") | |||
end | |||
if d["MATK-Based"] then | |||
table.insert(detail, "MATK-based") | |||
end | |||
if #detail > 0 then | |||
seg = seg .. " – " .. table.concat(detail, ", ") | |||
end | |||
table.insert(parts, seg) | |||
end | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | |||
local function formatReflectDamage(list) | |||
if type(list) ~= "table" or #list == 0 then | |||
return nil | return nil | ||
end | end | ||
local parts = {} | |||
for _, d in ipairs(list) do | |||
if type(d) == "table" then | |||
local base = d["Base %"] | |||
local per = d["Per Level %"] | |||
local seg = "Reflect" | |||
local detail = {} | |||
if base ~= nil then | |||
table.insert(detail, string.format("Base %s%%", tostring(base))) | |||
end | |||
if per ~= nil then | |||
table.insert(detail, string.format("%s%% / Lv", tostring(per))) | |||
end | |||
if #detail > 0 then | |||
seg = seg .. " – " .. table.concat(detail, ", ") | |||
end | |||
table.insert(parts, seg) | |||
end | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | end | ||
local function | local function formatScaling(list) | ||
if type( | if type(list) ~= "table" or #list == 0 then | ||
return nil | return nil | ||
end | end | ||
local parts = {} | |||
for _, s in ipairs(list) do | |||
if type(s) == "table" then | |||
local name = s["Scaling Name"] or s["Scaling ID"] or "Unknown" | |||
local pct = s.Percent | |||
local seg = name | |||
local detail = {} | |||
if pct ~= nil then | |||
table.insert(detail, string.format("%s%%", tostring(pct))) | |||
end | |||
if s["ATK-Based"] then | |||
table.insert(detail, "ATK-based") | |||
end | |||
if s["MATK-Based"] then | |||
table.insert(detail, "MATK-based") | |||
end | |||
if #detail > 0 then | |||
seg = seg .. " – " .. table.concat(detail, ", ") | |||
end | |||
table.insert(parts, seg) | |||
end | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | |||
local function formatArea(area) | |||
if type(area) ~= "table" then | |||
return nil | |||
end | |||
local parts = {} | local parts = {} | ||
local size = area["Area Size"] | |||
if size and size ~= "" then | |||
table.insert(parts, "Size: " .. tostring(size)) | |||
end | |||
local dist = area["Area Distance"] | |||
local eff = area["Effective Distance"] | |||
local distText = formatBasePer(dist) | |||
if distText then | |||
table.insert(parts, "Distance: " .. distText) | |||
end | |||
if eff ~= nil then | |||
table.insert(parts, string.format("Effective: %s", tostring(eff))) | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | |||
local function formatTimingBlock(bt) | |||
if type(bt) ~= "table" then | |||
return nil | |||
end | |||
local parts = {} | |||
end | |||
local function add(name, key) | |||
local block = bt[key] | |||
local txt = formatBasePer(block) | |||
if txt then | if txt then | ||
table.insert(parts, txt) | table.insert(parts, name .. ": " .. txt) | ||
end | end | ||
end | |||
add("Cast Time", "Cast Time") | |||
add("Cooldown", "Cooldown") | |||
add("Duration", "Duration") | |||
if bt["Effect Cast Time"] ~= nil then | |||
table.insert(parts, "Effect Cast Time: " .. tostring(bt["Effect Cast Time"])) | |||
end | |||
if bt["Damage Delay"] ~= nil then | |||
table.insert(parts, "Damage Delay: " .. tostring(bt["Damage Delay"])) | |||
end | |||
if bt["Effect Remove Delay"] ~= nil then | |||
table.insert(parts, "Effect Remove Delay: " .. tostring(bt["Effect Remove Delay"])) | |||
end | end | ||
| Line 115: | Line 259: | ||
return nil | return nil | ||
end | end | ||
return table.concat(parts, " | return table.concat(parts, "<br />") | ||
end | end | ||
local function | local function formatResourceCost(rc) | ||
if type( | if type(rc) ~= "table" then | ||
return nil | return nil | ||
end | |||
local parts = {} | |||
local mana = rc["Mana Cost"] | |||
local hp = rc["Health Cost"] | |||
local manaTxt = formatBasePer(mana) | |||
if manaTxt then | |||
table.insert(parts, "MP: " .. manaTxt) | |||
end | |||
local hpTxt = formatBasePer(hp) | |||
if hpTxt then | |||
table.insert(parts, "HP: " .. hpTxt) | |||
end | end | ||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | |||
local function formatCombo(combo) | |||
if type(combo) ~= "table" then | |||
return nil | |||
end | |||
local parts = {} | |||
if combo.Type then | |||
table.insert(parts, "Type: " .. tostring(combo.Type)) | |||
end | |||
if combo.Duration ~= nil then | |||
table.insert(parts, "Duration: " .. tostring(combo.Duration)) | |||
end | |||
if combo.Percent ~= nil then | |||
table.insert(parts, string.format("Bonus: %s%%", tostring(combo.Percent * 100))) | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, ", ") | |||
end | |||
local function formatMechanicEffects(effects) | |||
if type(effects) ~= "table" then | |||
return nil | |||
end | |||
local parts = {} | |||
for name, block in pairs(effects) do | |||
if type(block) == "table" then | |||
local bp = formatBasePer(block) | |||
local seg = name | |||
if bp then | |||
seg = seg .. " – " .. bp | |||
end | |||
table.insert(parts, seg) | |||
end | |||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | |||
local function formatModifiers(mods) | |||
if type(mods) ~= "table" then | |||
return nil | |||
end | |||
local parts = {} | local parts = {} | ||
local function collect(label, sub) | |||
local | if type(sub) ~= "table" then | ||
if | return | ||
table.insert(parts, string.format("%s: % | end | ||
local flags = {} | |||
for k, v in pairs(sub) do | |||
if v then | |||
table.insert(flags, k) | |||
end | |||
end | |||
table.sort(flags) | |||
if #flags > 0 then | |||
table.insert(parts, string.format("%s: %s", label, table.concat(flags, ", "))) | |||
end | end | ||
end | end | ||
collect("Movement", mods["Movement Modifiers"]) | |||
collect("Combat", mods["Combat Modifiers"]) | |||
collect("Special", mods["Special Modifiers"]) | |||
if #parts == 0 then | if #parts == 0 then | ||
return nil | return nil | ||
end | end | ||
return table.concat(parts, " | return table.concat(parts, "<br />") | ||
end | end | ||
| Line 144: | Line 363: | ||
return nil | return nil | ||
end | end | ||
local parts = {} | local parts = {} | ||
for _, s in ipairs(list) do | for _, s in ipairs(list) do | ||
local scope | if type(s) == "table" then | ||
local scope = s.Scope or "Target" | |||
local name = s["Status Name"] or s["Status ID"] or "Unknown status" | |||
local seg = scope .. " – " .. name | |||
local detail = {} | |||
seg = | |||
local dur = s.Duration | |||
if type(dur) == "table" then | |||
local t = formatBasePer(dur) | |||
if t then | |||
table.insert(detail, "Duration " .. t) | |||
end | |||
end | |||
local ch = s.Chance | |||
if type(ch) == "table" then | |||
local t = formatBasePer(ch) | |||
if t then | |||
table.insert(detail, "Chance " .. t) | |||
end | |||
end | |||
if s["Fixed Duration"] then | |||
table.insert(detail, "Fixed duration") | |||
end | |||
if #detail > 0 then | |||
seg = seg .. " (" .. table.concat(detail, ", ") .. ")" | |||
end | |||
table.insert(parts, seg) | |||
table.insert( | |||
end | end | ||
end | |||
if #parts == 0 then | |||
return nil | |||
end | |||
return table.concat(parts, "<br />") | |||
end | |||
local function formatStatusRemoval(list) | |||
if type(list) ~= "table" or #list == 0 then | |||
return nil | |||
end | |||
local parts = {} | |||
for _, r in ipairs(list) do | |||
if type(r) == "table" then | |||
local names = r["Status Name"] | |||
local label | |||
if type(names) == "table" then | |||
label = table.concat(names, ", ") | |||
elseif type(names) == "string" then | |||
label = names | |||
else | |||
label = "Status" | |||
end | |||
local bp = formatBasePer(r) | |||
local seg = label | |||
if bp then | |||
seg = seg .. " – " .. bp | |||
end | |||
table.insert(parts, seg) | |||
end | end | ||
end | end | ||
if #parts == 0 then | |||
return table.concat(parts, " | return nil | ||
end | |||
return table.concat(parts, "<br />") | |||
end | end | ||
local function formatEvents(list) | |||
local | if type(list) ~= "table" or #list == 0 then | ||
return nil | |||
end | |||
local parts = {} | |||
for _, ev in ipairs(list) do | |||
if type(ev) == "table" then | |||
local action = ev.Action or "On event" | |||
local name = ev["Skill Name"] or ev["Skill ID"] or "Unknown skill" | |||
local seg = string.format("%s → %s", action, name) | |||
table.insert(parts, seg) | |||
end | |||
end | |||
if #parts == 0 then | |||
return nil | return nil | ||
end | end | ||
return table.concat(parts, "<br />") | |||
end | end | ||
-- | ---------------------------------------------------------------------- | ||
local function | -- User matching (for auto lists on class pages) | ||
if not | ---------------------------------------------------------------------- | ||
return | |||
local function skillMatchesUser(rec, userName) | |||
if type(rec) ~= "table" or not userName or userName == "" then | |||
return false | |||
end | |||
local users = rec.Users | |||
if type(users) ~= "table" then | |||
return false | |||
end | end | ||
local | |||
for _, | local userLower = mw.ustring.lower(userName) | ||
local function listHas(list) | |||
if type(list) ~= "table" then | |||
return false | |||
end | |||
for _, v in ipairs(list) do | |||
if type(v) == "string" and mw.ustring.lower(v) == userLower then | |||
return true | |||
end | |||
end | end | ||
return false | |||
end | end | ||
return | |||
if listHas(users.Classes) then return true end | |||
if listHas(users.Summons) then return true end | |||
if listHas(users.Monsters) then return true end | |||
if listHas(users.Events) then return true end | |||
return false | |||
end | end | ||
| Line 207: | Line 498: | ||
root:addClass("wikitable spiritvale-skill-infobox") | root:addClass("wikitable spiritvale-skill-infobox") | ||
-- | -- ========================================================== | ||
-- Top "hero" row: icon + name (left), description (right) | |||
-- ========================================================== | |||
local icon = rec.Icon | local icon = rec.Icon | ||
local title = rec.Name or rec["Internal Name"] or "Unknown Skill" | local title = rec.Name or rec["Internal Name"] or "Unknown Skill" | ||
local desc = rec.Description or "" | |||
local headerRow = root:tag("tr") | |||
headerRow:addClass("spiritvale-infobox-main") | |||
-- Left cell: icon + name | |||
local leftCell = headerRow:tag("th") | |||
leftCell:addClass("spiritvale-infobox-main-left") | |||
local | local leftInner = leftCell:tag("div") | ||
leftInner:addClass("spiritvale-infobox-main-left-inner") | |||
if icon and icon ~= "" then | if icon and icon ~= "" then | ||
leftInner:wikitext(string.format("[[File:%s|80px|link=]]", icon)) | |||
end | |||
leftInner:tag("div") | |||
:addClass("spiritvale-infobox-title") | |||
:wikitext(title) | |||
-- Right cell: italic description | |||
local rightCell = headerRow:tag("td") | |||
rightCell:addClass("spiritvale-infobox-main-right") | |||
local rightInner = rightCell:tag("div") | |||
rightInner:addClass("spiritvale-infobox-main-right-inner") | |||
if desc ~= "" then | |||
rightInner:tag("div") | |||
:addClass("spiritvale-infobox-description") | |||
:wikitext(string.format("''%s''", desc)) | |||
end | end | ||
-- | ------------------------------------------------------------------ | ||
addRow(root, "Description", rec.Description) | -- General | ||
------------------------------------------------------------------ | |||
addSectionHeader(root, "General") | |||
-- Description now lives in the hero row. | |||
-- addRow(root, "Description", rec.Description) | |||
addRow(root, "Max level", rec["Max Level"] and tostring(rec["Max Level"])) | addRow(root, "Max level", rec["Max Level"] and tostring(rec["Max Level"])) | ||
local users = rec.Users or {} | local users = rec.Users or {} | ||
addRow(root, "Classes", listToText(users.Classes)) | addRow(root, "Classes", listToText(users.Classes)) | ||
| Line 233: | Line 552: | ||
addRow(root, "Events", listToText(users.Events)) | addRow(root, "Events", listToText(users.Events)) | ||
------------------------------------------------------------------ | |||
-- Requirements | -- Requirements | ||
------------------------------------------------------------------ | |||
local req = rec.Requirements or {} | local req = rec.Requirements or {} | ||
if (req["Required Skills"] and #req["Required Skills"] > 0) | |||
or (req["Required Weapons"] and #req["Required Weapons"] > 0) | |||
or (req["Required Stances"] and #req["Required Stances"] > 0) then | |||
addSectionHeader(root, "Requirements") | |||
if type(req["Required Skills"]) == "table" and #req["Required Skills"] > 0 then | |||
local skillParts = {} | |||
for _, rs in ipairs(req["Required Skills"]) do | |||
local name = rs["Skill Name"] or rs["Skill ID"] or "Unknown" | |||
local level = rs["Required Level"] | |||
if level then | |||
table.insert(skillParts, string.format("%s (Lv.%s)", name, level)) | |||
else | |||
table.insert(skillParts, name) | |||
end | |||
end | end | ||
addRow(root, "Required skills", table.concat(skillParts, ", ")) | |||
end | end | ||
addRow(root, "Required | |||
addRow(root, "Required weapons", listToText(req["Required Weapons"])) | |||
addRow(root, "Required stances", listToText(req["Required Stances"])) | |||
end | end | ||
------------------------------------------------------------------ | |||
-- Type | |||
------------------------------------------------------------------ | |||
local typeBlock = rec.Type or {} | |||
if next(typeBlock) ~= nil then | |||
addSectionHeader(root, "Type") | |||
local dt = typeBlock["Damage Type"] | |||
if type(dt) == "table" and dt.Name then | |||
addRow(root, "Damage type", dt.Name) | |||
end | |||
local et = typeBlock["Element Type"] | |||
if type(et) == "table" and et.Name then | |||
addRow(root, "Element", et.Name) | |||
end | |||
local tt = typeBlock["Target Type"] | |||
if type(tt) == "table" and tt.Name then | |||
addRow(root, "Target", tt.Name) | |||
end | |||
local ct = typeBlock["Cast Type"] | |||
if type(ct) == "table" and ct.Name then | |||
addRow(root, "Cast type", ct.Name) | |||
end | |||
end | |||
------------------------------------------------------------------ | |||
-- Mechanics | -- Mechanics | ||
local mech | ------------------------------------------------------------------ | ||
local mech = rec.Mechanics or {} | |||
if next(mech) ~= nil then | |||
addSectionHeader(root, "Mechanics") | |||
if mech.Range ~= nil then | |||
addRow(root, "Range", tostring(mech.Range)) | |||
end | |||
local areaText = formatArea(mech.Area) | |||
addRow(root, "Area", areaText) | |||
if mech["Autocast Multiplier"] ~= nil then | |||
addRow(root, "Autocast multiplier", tostring(mech["Autocast Multiplier"])) | |||
end | |||
local btText = formatTimingBlock(mech["Basic Timings"]) | |||
addRow(root, "Timing", btText) | |||
local rcText = formatResourceCost(mech["Resource Cost"]) | |||
addRow(root, "Resource cost", rcText) | |||
local comboText = formatCombo(mech.Combo) | |||
addRow(root, "Combo", comboText) | |||
local effText = formatMechanicEffects(mech.Effects) | |||
addRow(root, "Special mechanics", effText) | |||
end | end | ||
------------------------------------------------------------------ | |||
-- Damage & Healing | |||
------------------------------------------------------------------ | |||
local dmg = rec.Damage or {} | |||
if next(dmg) ~= nil then | |||
addSectionHeader(root, "Damage and scaling") | |||
if dmg["Healing Present"] then | |||
addRow(root, "Healing", "Yes") | |||
end | |||
local mainText = formatMainDamage(dmg["Main Damage"]) | |||
addRow(root, "Main damage", mainText) | |||
local reflText = formatReflectDamage(dmg["Reflect Damage"]) | |||
addRow(root, "Reflect damage", reflText) | |||
local scaleText = formatScaling(dmg.Scaling) | |||
addRow(root, "Scaling", scaleText) | |||
end | |||
------------------------------------------------------------------ | |||
-- Modifiers | |||
------------------------------------------------------------------ | |||
local modsText = formatModifiers(rec.Modifiers) | |||
if modsText then | |||
addSectionHeader(root, "Modifiers") | |||
addRow(root, "Flags", modsText) | |||
end | |||
-- Status | ------------------------------------------------------------------ | ||
-- Status | |||
------------------------------------------------------------------ | |||
local statusApps = formatStatusApplications(rec["Status Applications"]) | local statusApps = formatStatusApplications(rec["Status Applications"]) | ||
addRow(root, " | local statusRem = formatStatusRemoval(rec["Status Removal"]) | ||
if statusApps or statusRem then | |||
addSectionHeader(root, "Status effects") | |||
addRow(root, "Applies", statusApps) | |||
addRow(root, "Removes", statusRem) | |||
end | |||
------------------------------------------------------------------ | |||
-- Events | |||
------------------------------------------------------------------ | |||
local eventsText = formatEvents(rec.Events) | |||
if eventsText then | |||
addSectionHeader(root, "Events") | |||
addRow(root, "Triggers", eventsText) | |||
end | |||
------------------------------------------------------------------ | |||
-- Notes | |||
------------------------------------------------------------------ | |||
if type(rec.Notes) == "table" and #rec.Notes > 0 then | |||
addSectionHeader(root, "Notes") | |||
addRow(root, "Notes", table.concat(rec.Notes, "<br />")) | |||
end | |||
return tostring(root) | |||
end | |||
---------------------------------------------------------------------- | |||
-- Public: list all skills for a given user/class | |||
---------------------------------------------------------------------- | |||
function p.listForUser(frame) | |||
local args = getArgs(frame) | |||
-- Prefer explicit param, then unnamed, then fall back to the current page name. | |||
local userName = args.user or args[1] | |||
if not userName or userName == "" then | |||
userName = mw.title.getCurrentTitle().text | |||
end | |||
if not userName or userName == "" then | |||
return "<strong>No user name provided to Skill list.</strong>" | |||
end | |||
local dataset = getSkills() | |||
local matches = {} | |||
for _, rec in ipairs(dataset.records or {}) do | |||
if skillMatchesUser(rec, userName) then | |||
table.insert(matches, rec) | |||
end | |||
end | |||
if #matches == 0 then | |||
return string.format( | |||
"<strong>No skills found for:</strong> %s", | |||
mw.text.nowiki(userName) | |||
) | |||
end | |||
local root = mw.html.create("div") | |||
root:addClass("spiritvale-skill-list") | |||
for _, rec in ipairs(matches) do | |||
root:wikitext(buildInfobox(rec)) | |||
end | |||
return tostring(root) | return tostring(root) | ||
| Line 297: | Line 744: | ||
---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ||
-- Public | -- Public: single-skill or auto-list dispatcher | ||
---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ||
| Line 313: | Line 760: | ||
local rec | local rec | ||
-- 1) Prefer display Name | -- 1) Prefer display Name | ||
if name and name ~= "" then | if name and name ~= "" then | ||
rec = findSkillByName(name) | rec = findSkillByName(name) | ||
end | end | ||
-- 2) Fallback: internal ID | -- 2) Fallback: internal ID | ||
if not rec and id and id ~= "" then | if not rec and id and id ~= "" then | ||
rec = getSkillById(id) | rec = getSkillById(id) | ||
end | end | ||
-- 3) If still nothing, decide if this is "list mode" or truly unknown. | |||
if not rec then | if not rec then | ||
local pageTitle = mw.title.getCurrentTitle() | |||
local pageName = pageTitle and pageTitle.text or "" | |||
local noExplicitArgs = | |||
(not raw1 or raw1 == "") and | |||
(not args.name or args.name == "") and | |||
(not id or id == "") | |||
-- Case A: {{Skill}} with no parameters on a page → list for that page name. | |||
if noExplicitArgs then | |||
return p.listForUser(frame) | |||
end | |||
-- Case B: {{Skill|Acolyte}} on the "Acolyte" page and no id → treat as list. | |||
if name and name ~= "" and name == pageName and (not id or id == "") then | |||
return p.listForUser(frame) | |||
end | |||
-- Otherwise, genuinely unknown skill. | |||
local label = name or id or "?" | local label = name or id or "?" | ||
return string.format( | return string.format( | ||
| Line 332: | Line 799: | ||
end | end | ||
-- Normal single-skill behavior | |||
return buildInfobox(rec) | return buildInfobox(rec) | ||
end | end | ||
return p | return p | ||