More actions
Content deleted Content added
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode Tag: Reverted |
||
Line 1: | Line 1: | ||
local p = {} |
local p = {} |
||
-- Escape a string for use inside a Lua pattern |
|||
local p = {} |
|||
local function escapePattern(s) |
|||
return (s:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")) |
|||
end |
|||
-- Does a page belong to a wiki category (by scanning its wikitext for [[Category:...]]) |
|||
local function pageInCategory(pagetitle, cat) |
|||
if not pagetitle then return false end |
|||
local title = mw.title.new(pagetitle) |
|||
if not title or not title.exists then return false end |
|||
local content = title:getContent() |
|||
if not content then return false end |
|||
-- match [[Category:Cat]] or [[Category:Cat|sort]] |
|||
local pat = "%[%[Category:" .. escapePattern(cat) .. "[^%]]*%]%]" |
|||
return mw.ustring.find(content, pat) ~= nil |
|||
end |
|||
-- Build AE template from an ability object |
|||
local function aeTemplate(a) |
|||
local parts = {"{{AE|", a.name} |
|||
if a.limited and a.limited ~= "" then table.insert(parts, "|limited=" .. a.limited) end |
|||
if a.improved and a.improved ~= "" then table.insert(parts, "|improved=" .. a.improved) end |
|||
if a.gifted then table.insert(parts, "|gifted=1") end |
|||
if a.adept then table.insert(parts, "|adept=1") end |
|||
table.insert(parts, "}}") |
|||
return table.concat(parts) |
|||
end |
|||
function p.c(frame) |
function p.c(frame) |
||
Line 7: | Line 33: | ||
local rawAbilities = args['a'] or '' |
local rawAbilities = args['a'] or '' |
||
-- Prepopulate defaults |
|||
-- Parse abilities into a structured table |
|||
local abilities = {} |
local abilities = {} |
||
local indexByName = {} |
|||
local function addAbility(obj, isDefault) |
|||
local key = mw.text.trim(obj.name or "") |
|||
if key == "" then return end |
|||
obj.name = key |
|||
if indexByName[key] then |
|||
abilities[indexByName[key]] = obj |
|||
else |
|||
table.insert(abilities, obj) |
|||
indexByName[key] = #abilities |
|||
end |
|||
if isDefault then abilities[indexByName[key]]._isDefault = true end |
|||
end |
|||
local function removeByName(name) |
|||
local i = indexByName[name] |
|||
if not i then return end |
|||
table.remove(abilities, i) |
|||
-- rebuild index |
|||
indexByName = {} |
|||
for idx, ab in ipairs(abilities) do |
|||
indexByName[ab.name] = idx |
|||
end |
|||
end |
|||
-- Defaults |
|||
local defaults = { |
|||
"Normal Intelligence", |
|||
"Normal Strength", |
|||
"Normal Movement", |
|||
"Normal Sneak", |
|||
"Normal Perception", |
|||
} |
|||
for _, n in ipairs(defaults) do |
|||
addAbility({ |
|||
name = n, limited = "", improved = "", gifted = false, adept = false |
|||
}, true) |
|||
end |
|||
-- Parse incoming abilities |
|||
local incomingNames = {} -- keep a list to check categories against (only incoming) |
|||
for ability in mw.text.gsplit(rawAbilities, ";;", true) do |
for ability in mw.text.gsplit(rawAbilities, ";;", true) do |
||
ability = mw.text.trim(ability) |
ability = mw.text.trim(ability) |
||
Line 16: | Line 84: | ||
local gifted, adept = false, false |
local gifted, adept = false, false |
||
-- flags |
|||
if mw.ustring.find(ability, "%-g%-") then gifted = true end |
if mw.ustring.find(ability, "%-g%-") then gifted = true end |
||
if mw.ustring.find(ability, "%-a%-") then adept = true end |
if mw.ustring.find(ability, "%-a%-") then adept = true end |
||
-- notes (order-insensitive, tolerate any following marker) |
|||
local limitedMatch = mw.ustring.match(ability, "%-l%-(.-)(%-[liag]%-|$)") |
local limitedMatch = mw.ustring.match(ability, "%-l%-(.-)(%-[liag]%-|$)") |
||
or mw.ustring.match(ability, "%-l%-(.+)$") |
or mw.ustring.match(ability, "%-l%-(.+)$") |
||
Line 29: | Line 95: | ||
if improvedMatch then improved = mw.text.trim(improvedMatch) end |
if improvedMatch then improved = mw.text.trim(improvedMatch) end |
||
-- clean name |
-- clean name |
||
name = mw.ustring.gsub(name, "%-l%-.+", "") |
name = mw.ustring.gsub(name, "%-l%-.+", "") |
||
name = mw.ustring.gsub(name, "%-i%-.+", "") |
name = mw.ustring.gsub(name, "%-i%-.+", "") |
||
Line 36: | Line 102: | ||
name = mw.text.trim(name) |
name = mw.text.trim(name) |
||
addAbility({ |
|||
table.insert(abilities, { |
|||
name = name, |
name = name, |
||
limited = limited, |
limited = limited, |
||
Line 42: | Line 108: | ||
gifted = gifted, |
gifted = gifted, |
||
adept = adept |
adept = adept |
||
}) |
}, false) |
||
table.insert(incomingNames, name) |
|||
end |
end |
||
end |
end |
||
-- If any incoming ability is in the mapped category, remove the corresponding default |
|||
-- Sort alphabetically by name (stable) |
|||
local catMap = { |
|||
table.sort(abilities, function(a, b) return a.name < b.name end) |
|||
["Normal Intelligence"] = "INT setting abilities", |
|||
["Normal Strength"] = "STR setting abilities", |
|||
["Normal Movement"] = "MOV setting abilities", |
|||
["Normal Sneak"] = "SNK setting abilities", |
|||
["Normal Perception"] = "PER setting abilities", |
|||
} |
|||
-- Track which default to remove |
|||
-- Build the out string (NO visible separators between AE templates) |
|||
local |
local shouldRemove = { |
||
["Normal Intelligence"] = false, |
|||
for _, a in ipairs(abilities) do |
|||
["Normal Strength"] = false, |
|||
local t = {"{{AE|", a.name} |
|||
["Normal Movement"] = false, |
|||
if a.limited ~= "" then table.insert(t, "|limited=" .. a.limited) end |
|||
["Normal Sneak"] = false, |
|||
if a.improved ~= "" then table.insert(t, "|improved=" .. a.improved) end |
|||
["Normal Perception"] = false, |
|||
if a.gifted then table.insert(t, "|gifted=1") end |
|||
} |
|||
if a.adept then table.insert(t, "|adept=1") end |
|||
table.insert(t, "}}") |
|||
for _, inName in ipairs(incomingNames) do |
|||
table.insert(transclusions, table.concat(t)) |
|||
-- Check each mapped category; if the page is in that cat, flag removal |
|||
for normalName, cat in pairs(catMap) do |
|||
if not shouldRemove[normalName] then |
|||
if pageInCategory(inName, cat) then |
|||
shouldRemove[normalName] = true |
|||
end |
|||
end |
|||
end |
|||
end |
end |
||
for normalName, flag in pairs(shouldRemove) do |
|||
-- Use "" (or "\n") so no semicolons are emitted |
|||
if flag then |
|||
local inner = table.concat(transclusions, "") -- <- changed from ";; " |
|||
removeByName(normalName) |
|||
end |
|||
end |
|||
-- Sort alphabetically by name |
|||
table.sort(abilities, function(a, b) return a.name < b.name end) |
|||
-- Assemble output (no semicolons) |
|||
local outParts = {} |
|||
for _, a in ipairs(abilities) do |
|||
table.insert(outParts, aeTemplate(a)) |
|||
end |
|||
local inner = table.concat(outParts, "") |
|||
local out = '<div class="expandable-table"><div>' .. frame:preprocess(inner) .. '</div></div>' |
local out = '<div class="expandable-table"><div>' .. frame:preprocess(inner) .. '</div></div>' |
||
return out |
return out |
||
end |
end |
Revision as of 02:02, 12 August 2025
Documentation for this module may be created at Module:C/doc
local p = {}
-- Escape a string for use inside a Lua pattern
local function escapePattern(s)
return (s:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1"))
end
-- Does a page belong to a wiki category (by scanning its wikitext for [[Category:...]])
local function pageInCategory(pagetitle, cat)
if not pagetitle then return false end
local title = mw.title.new(pagetitle)
if not title or not title.exists then return false end
local content = title:getContent()
if not content then return false end
-- match [[Category:Cat]] or [[Category:Cat|sort]]
local pat = "%[%[Category:" .. escapePattern(cat) .. "[^%]]*%]%]"
return mw.ustring.find(content, pat) ~= nil
end
-- Build AE template from an ability object
local function aeTemplate(a)
local parts = {"{{AE|", a.name}
if a.limited and a.limited ~= "" then table.insert(parts, "|limited=" .. a.limited) end
if a.improved and a.improved ~= "" then table.insert(parts, "|improved=" .. a.improved) end
if a.gifted then table.insert(parts, "|gifted=1") end
if a.adept then table.insert(parts, "|adept=1") end
table.insert(parts, "}}")
return table.concat(parts)
end
function p.c(frame)
local args = frame.args
local rawAbilities = args['a'] or ''
-- Prepopulate defaults
local abilities = {}
local indexByName = {}
local function addAbility(obj, isDefault)
local key = mw.text.trim(obj.name or "")
if key == "" then return end
obj.name = key
if indexByName[key] then
abilities[indexByName[key]] = obj
else
table.insert(abilities, obj)
indexByName[key] = #abilities
end
if isDefault then abilities[indexByName[key]]._isDefault = true end
end
local function removeByName(name)
local i = indexByName[name]
if not i then return end
table.remove(abilities, i)
-- rebuild index
indexByName = {}
for idx, ab in ipairs(abilities) do
indexByName[ab.name] = idx
end
end
-- Defaults
local defaults = {
"Normal Intelligence",
"Normal Strength",
"Normal Movement",
"Normal Sneak",
"Normal Perception",
}
for _, n in ipairs(defaults) do
addAbility({
name = n, limited = "", improved = "", gifted = false, adept = false
}, true)
end
-- Parse incoming abilities
local incomingNames = {} -- keep a list to check categories against (only incoming)
for ability in mw.text.gsplit(rawAbilities, ";;", true) do
ability = mw.text.trim(ability)
if ability ~= "" then
local name = ability
local limited, improved = "", ""
local gifted, adept = false, false
if mw.ustring.find(ability, "%-g%-") then gifted = true end
if mw.ustring.find(ability, "%-a%-") then adept = true end
local limitedMatch = mw.ustring.match(ability, "%-l%-(.-)(%-[liag]%-|$)")
or mw.ustring.match(ability, "%-l%-(.+)$")
if limitedMatch then limited = mw.text.trim(limitedMatch) end
local improvedMatch = mw.ustring.match(ability, "%-i%-(.-)(%-[liag]%-|$)")
or mw.ustring.match(ability, "%-i%-(.+)$")
if improvedMatch then improved = mw.text.trim(improvedMatch) end
-- clean name
name = mw.ustring.gsub(name, "%-l%-.+", "")
name = mw.ustring.gsub(name, "%-i%-.+", "")
name = mw.ustring.gsub(name, "%-g%-", "")
name = mw.ustring.gsub(name, "%-a%-", "")
name = mw.text.trim(name)
addAbility({
name = name,
limited = limited,
improved = improved,
gifted = gifted,
adept = adept
}, false)
table.insert(incomingNames, name)
end
end
-- If any incoming ability is in the mapped category, remove the corresponding default
local catMap = {
["Normal Intelligence"] = "INT setting abilities",
["Normal Strength"] = "STR setting abilities",
["Normal Movement"] = "MOV setting abilities",
["Normal Sneak"] = "SNK setting abilities",
["Normal Perception"] = "PER setting abilities",
}
-- Track which default to remove
local shouldRemove = {
["Normal Intelligence"] = false,
["Normal Strength"] = false,
["Normal Movement"] = false,
["Normal Sneak"] = false,
["Normal Perception"] = false,
}
for _, inName in ipairs(incomingNames) do
-- Check each mapped category; if the page is in that cat, flag removal
for normalName, cat in pairs(catMap) do
if not shouldRemove[normalName] then
if pageInCategory(inName, cat) then
shouldRemove[normalName] = true
end
end
end
end
for normalName, flag in pairs(shouldRemove) do
if flag then
removeByName(normalName)
end
end
-- Sort alphabetically by name
table.sort(abilities, function(a, b) return a.name < b.name end)
-- Assemble output (no semicolons)
local outParts = {}
for _, a in ipairs(abilities) do
table.insert(outParts, aeTemplate(a))
end
local inner = table.concat(outParts, "")
local out = '<div class="expandable-table"><div>' .. frame:preprocess(inner) .. '</div></div>'
return out
end
return p