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 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 not list or #list == 0 then
     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 not block or type(block) ~= "table" then
     if type(block) ~= "table" then
         return nil
         return nil
     end
     end
Line 60: Line 70:


local function formatManaCost(block)
local function formatManaCost(block)
     if not block or type(block) ~= "table" then
     if type(block) ~= "table" then
         return nil
         return nil
     end
     end
Line 79: Line 89:


local function formatMainDamage(damageTable)
local function formatMainDamage(damageTable)
     if not damageTable or #damageTable == 0 then
     if type(damageTable) ~= "table" or #damageTable == 0 then
         return nil
         return nil
     end
     end


    -- Current schema only has one entry, but we’ll still handle arrays.
     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 not scalingList or #scalingList == 0 then
     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 not list or #list == 0 then
     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
            -- Stored as 0–1; we’ll keep it raw to avoid guessing units.
             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)
-- Public: infobox
local function getSkillById(id)
----------------------------------------------------------------------
 
function p.infobox(frame)
    local args = getArgs(frame)
    local id  = args.id or args[1]
 
     if not id or id == "" then
     if not id or id == "" then
         return "[[Category:Pages with missing skill id]]"
         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()
     local rec     = dataset.byId[id]
     for _, rec in ipairs(dataset.records or {}) do
        if rec["Name"] == name then
            return rec
        end
    end
    return nil
end


    if not rec then
----------------------------------------------------------------------
        return "[[Category:Pages with unknown skill id|" .. mw.text.nowiki(id) .. "]]"
-- Infobox builder
    end
----------------------------------------------------------------------


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 id
     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 .. (title or id)
     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)


     -- We could add Status Removal here later if you want it visible.
     return tostring(root)
end
 
----------------------------------------------------------------------
-- Public entry point
----------------------------------------------------------------------
 
function p.infobox(frame)
    local args = getArgs(frame)


     return tostring(root)
    -- 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