Module:GameSkills: Difference between revisions
From SpiritVale Wiki
More actions
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
-- Module:GameSkills | |||
-- | |||
-- Renders skill data (from Data:skills.json) into an infobox/table. | |||
-- Data is loaded via Module:GameData. | |||
-- | |||
-- Supported usage patterns (via Template:Skill): | |||
-- {{Skill|Bash}} -- uses display Name (recommended) | |||
-- {{Skill|name=Bash}} -- explicit name | |||
-- {{Skill|id=Bash_InternalId}} -- internal ID (power use) | |||
local GameData = require("Module:GameData") | local GameData = require("Module:GameData") | ||
| Line 26: | Line 36: | ||
local function listToText(list) | local function listToText(list) | ||
if | if type(list) ~= "table" or #list == 0 then | ||
return nil | return nil | ||
end | end | ||
| Line 42: | Line 52: | ||
local function formatBasePer(block) | local function formatBasePer(block) | ||
if | if type(block) ~= "table" then | ||
return nil | return nil | ||
end | end | ||
| Line 60: | Line 70: | ||
local function formatManaCost(block) | local function formatManaCost(block) | ||
if | if type(block) ~= "table" then | ||
return nil | return nil | ||
end | end | ||
| Line 79: | Line 89: | ||
local function formatMainDamage(damageTable) | local function formatMainDamage(damageTable) | ||
if | if type(damageTable) ~= "table" or #damageTable == 0 then | ||
return nil | return nil | ||
end | end | ||
local parts = {} | local parts = {} | ||
for _, entry in ipairs(damageTable) do | for _, entry in ipairs(damageTable) do | ||
| Line 110: | Line 119: | ||
local function formatScaling(scalingList) | local function formatScaling(scalingList) | ||
if | if type(scalingList) ~= "table" or #scalingList == 0 then | ||
return nil | return nil | ||
end | end | ||
| Line 132: | Line 141: | ||
local function formatStatusApplications(list) | local function formatStatusApplications(list) | ||
if | if type(list) ~= "table" or #list == 0 then | ||
return nil | return nil | ||
end | end | ||
| Line 144: | Line 153: | ||
local seg = name | local seg = name | ||
if scope and scope ~= "" then | if scope and scope ~= "" then | ||
seg = scope .. ": " .. seg | seg = scope .. ": " .. seg | ||
| Line 154: | Line 162: | ||
end | end | ||
if chance then | if chance then | ||
table.insert(detailParts, string.format("Chance %.2f", chance)) | table.insert(detailParts, string.format("Chance %.2f", chance)) | ||
end | end | ||
| Line 168: | Line 175: | ||
end | end | ||
-- | -- Lookup by internal ID (for tools / power use) | ||
local function getSkillById(id) | |||
if not id or id == "" then | if not id or id == "" then | ||
return | return nil | ||
end | end | ||
local dataset = getSkills() | |||
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 | |||
end | |||
local dataset = getSkills() | local dataset = getSkills() | ||
for _, rec in ipairs(dataset.records or {}) do | |||
if rec["Name"] == name then | |||
return rec | |||
end | |||
end | |||
return nil | |||
end | |||
---------------------------------------------------------------------- | |||
-- Infobox builder | |||
---------------------------------------------------------------------- | |||
local function buildInfobox(rec) | |||
local root = mw.html.create("table") | local root = mw.html.create("table") | ||
root:addClass("wikitable spiritvale-skill-infobox") | root:addClass("wikitable spiritvale-skill-infobox") | ||
| Line 192: | Line 209: | ||
-- Header: icon + name | -- Header: icon + name | ||
local icon = rec.Icon | local icon = rec.Icon | ||
local title = rec.Name or | local title = rec.Name or rec["Internal Name"] or "Unknown Skill" | ||
local header = root:tag("tr") | local header = root:tag("tr") | ||
| Line 202: | Line 219: | ||
titleText = string.format("[[File:%s|64px|link=]] ", icon) | titleText = string.format("[[File:%s|64px|link=]] ", icon) | ||
end | end | ||
titleText = titleText .. | titleText = titleText .. title | ||
headerCell:wikitext(titleText) | headerCell:wikitext(titleText) | ||
-- Basic info | -- Basic info | ||
addRow(root, "Description", rec.Description) | 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"])) | ||
-- Users | -- Users | ||
local users = rec.Users or {} | local users = rec.Users or {} | ||
addRow(root, "Classes", listToText(users.Classes)) | addRow(root, "Classes", listToText(users.Classes)) | ||
| Line 220: | Line 233: | ||
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 then | if type(req["Required Skills"]) == "table" and #req["Required Skills"] > 0 then | ||
local skillParts = {} | local skillParts = {} | ||
for _, rs in ipairs(req["Required Skills"]) do | for _, rs in ipairs(req["Required Skills"]) do | ||
| Line 242: | Line 253: | ||
addRow(root, "Required stances", listToText(req["Required Stances"])) | addRow(root, "Required stances", listToText(req["Required Stances"])) | ||
-- Type | -- Type | ||
local t = rec.Type or {} | local t = rec.Type or {} | ||
local damageType = t["Damage Type"] and t["Damage Type"].Name | local damageType = t["Damage Type"] and t["Damage Type"].Name | ||
| Line 256: | Line 265: | ||
addRow(root, "Cast type", castType) | addRow(root, "Cast type", castType) | ||
-- Mechanics | -- Mechanics | ||
local mech = rec.Mechanics or {} | local mech = rec.Mechanics or {} | ||
local basicTimings = mech["Basic Timings"] or {} | local basicTimings = mech["Basic Timings"] or {} | ||
| Line 274: | Line 281: | ||
addRow(root, "Mana cost", manaCost) | addRow(root, "Mana cost", manaCost) | ||
-- Damage + Scaling | -- Damage + Scaling | ||
local dmg = rec.Damage or {} | local dmg = rec.Damage or {} | ||
local mainDmg = formatMainDamage(dmg["Main Damage"]) | local mainDmg = formatMainDamage(dmg["Main Damage"]) | ||
| Line 284: | Line 289: | ||
addRow(root, "Scaling", scaling) | addRow(root, "Scaling", scaling) | ||
-- Status interactions | -- Status interactions | ||
local statusApps = formatStatusApplications(rec["Status Applications"]) | local statusApps = formatStatusApplications(rec["Status Applications"]) | ||
addRow(root, "Status applications", statusApps) | addRow(root, "Status applications", statusApps) | ||
-- | return tostring(root) | ||
end | |||
---------------------------------------------------------------------- | |||
-- Public entry point | |||
---------------------------------------------------------------------- | |||
function p.infobox(frame) | |||
local args = getArgs(frame) | |||
return | -- Allow three styles: | ||
-- {{Skill|Bash}} -> args[1] = "Bash" (Name) | |||
-- {{Skill|name=Bash}} -> args.name = "Bash" | |||
-- {{Skill|id=Bash_Internal}} -> args.id = "Bash_Internal" | |||
local raw1 = args[1] | |||
local name = args.name or raw1 | |||
local id = args.id | |||
local rec | |||
-- 1) Prefer display Name (what editors will actually use) | |||
if name and name ~= "" then | |||
rec = findSkillByName(name) | |||
end | |||
-- 2) Fallback: internal ID if explicitly given | |||
if not rec and id and id ~= "" then | |||
rec = getSkillById(id) | |||
end | |||
if not rec then | |||
local label = name or id or "?" | |||
return string.format( | |||
"<strong>Unknown skill:</strong> %s[[Category:Pages with unknown skill|%s]]", | |||
mw.text.nowiki(label), | |||
label | |||
) | |||
end | |||
return buildInfobox(rec) | |||
end | end | ||
return p | return p | ||